How to Properly Use Controller and Service in Custom Plugin
It's actually quite simple.
First you need a form:

&lt;form method="post" id="myForm"&gt;
    &lt;!-- insert your route as an action parameter in camelCase --&gt;
    &lt;!-- pluginName/controllerName/methodName --&gt;
    &lt;input type="hidden" name="action" value="craftMailchimped/submittal/receiveEmail"&gt;
    &lt;input type="text" name="email"&gt;
    &lt;input type="button" id="submit" value="Submit"&gt;
&lt;/form&gt;


Then you have your javascript (I'll use jQuery ajax for that)

$("#submit").click(function(e){
    e.preventDefault();
    $.ajax({
        type: "post",
        url: '', //&lt;- leave the url blank.. always...
        data: $("#myForm").serialize(),
        success: function(data){
            console.log(data);
            if(data.success === true){
                alert(data.message);
            }else{
                //display your data.errors here
            }
        },
        error: function (XMLHttpRequest, textStatus) {
            console.log("Status: " + textStatus);
        }
    });
});


And your controller and this model

public function actionReceiveEmail() {
    $response = [
        'success'   =&gt; false,
        'message'   =&gt; Craft::t('something went wrong')
    ];

    $emailModel = new CraftMailchimped_EmailModel();
    $emailModel-&gt;email = craft()-&gt;request-&gt;getParam('email');

    if(craft()-&gt;yourServiceName-&gt;subscribe($emailModel)){
        $response['success'] = true;
        $response['message'] = Craft::t('wuhu great :D');
    }else{
        $response['errors'] = $emailModel-&gt;getErrors();
    }

    $this-&gt;returnJson($response);
}


Your service could contain this method

public function subscribe(CraftMailchimped_EmailModel $emailModel){
    if($success = $emailModel-&gt;validate()){
        //make your API calls
        $response = ......;
        if($response['error'] === 444){
            $emailModel-&gt;addError('email', Craft::t('Email is already taken'));
            $success = false;
        }
    }

    return $success;
}


So you are totally right with your points. In case you want to see how to manage records in your database take a look at this plugin Click I created it for learning purposes for someone else in this thread. Maybe you'll find it useful to learn some stuff like fetching objects from the database and inserting.

Edit
to resume 


You should always leave the url blank, define an action parameter for your route. The request type does not matter, it's the same for ajax and normal requests
Your Route is always pluginHandle/controllerName/functionName in camelCase
Your messages and responses should always be defined in your Controllers, your Services are just for logic that return true or false (or some objects like craft()-&gt;entries-&gt;getEntryById()), you can create models with validations for error messages you can use them like that: (validators will provide the translated messages)

// in your controller
$mailChimpModel;
if(craft()-&gt;mailchimp-&gt;subscribe($mailChimpModel)){
    $response['success'] = true;
}else{
    $response['errors'] = $mailChimpModel-&gt;getErrors();
}


$response['errors'] is an array with all field handles and the corresponding translated error messages like 'email' =&gt; ['This Mail is already in the list'] 
Crafts RequestService has all the methods you need to access the request variables. Those values are all safely escaped and secure, so you can be sure there won't be security measures. You can access parameters with craft()-&gt;request-&gt;getParam('key', default value);