4

I am using Alamofire to send a request to MailChimp to add a user to a list

MailChimp's docs say:

There are 2 authentication methods for the API: HTTP Basic authentication and OAuth2. The easiest way to authenticate is using HTTP Basic authentication. Enter any string as your username and supply your API Key as the password.

The request I wrote for Alamofire:

let params: [String : AnyObject] = ["email_address": email, "status": "subscribed", "merge_fields": [ "FNAME": name]]

guard let url = "https://us10.api.mailchimp.com/3.0/lists/<listID>/members/".stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) else { return }

Alamofire.request(.POST, url, parameters: params, encoding: .URL)
    .authenticate(user: "apiKey", password: "<apikey>")
    .responseJSON { response in

        if response.result.isFailure {

        }
        else if let responseJSON = response.result.value as? [String: AnyObject] {

        }
    }

I checked that the API key is correct by using it to access their playground: https://us1.api.mailchimp.com/playground/

The response I get back states that the API key was not included:

Your request did not include an API key.

Where have I gone wrong?

ekad
  • 14,436
  • 26
  • 44
  • 46
Abbey Jackson
  • 885
  • 10
  • 20
  • Aren't those fields POST parameters instead of standard authentication? – Andy Ibanez Aug 31 '16 at 05:05
  • @AndyIbanez https://github.com/Alamofire/Alamofire#http-basic-authentication I copied their example. – Abbey Jackson Aug 31 '16 at 05:43
  • I messed up entirely with my comment. I have used the Mailgun API and for some reason remembered it as requiring the credentials being sent in a POST. My apologies. Disregard my comment and look at the answers you received. – Andy Ibanez Aug 31 '16 at 13:11

4 Answers4

6

Swift 3

Make sure you take a look at MailChimp's Error Glossary. A 401 indicates that your API key is not being read properly.


For Swift 3, the header construction in Abbey Jackson's answer needs to be updated to this. Otherwise it totally works.

let credentialData = "AnyString:\(apiKey)".data(using: String.Encoding.utf8)!
let base64Credentials = credentialData.base64EncodedString()
let headers = ["Authorization": "Basic \(base64Credentials)"]

Here's an example that uses Request.authorizationHeader instead.

let apiKey: String = "xxxxxxxxxxxxxxx2b-us11" // note the 'us11'
let baseUrl: String = "https://us11.api.mailchimp.com/3.0" // note the 'us11'
let listId: String = "xxxxxx2f"

func createListMember() {

    let url = "\(baseUrl)/lists/\(listId)/members"

    guard let authorizationHeader = Request.authorizationHeader(user: "AnyString", password: apiKey) else {
        print("!authorizationHeader")
        return
    }

    let headers: HTTPHeaders = [
        authorizationHeader.key: authorizationHeader.value
    ]

    let parameters: Parameters = [
        "email_address": email,
        "status": "subscribed"
    ]

    // perform request (make sure you're using JSONEncoding.default)       
    Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers)
        //.authenticate(user: "AnyString", password: apiKey) // this doesn't work
        .validate()
        .responseJSON {(response) in
            print(response)
    }
}
Derek Soike
  • 11,238
  • 3
  • 79
  • 74
5

So MailChimp actually needs the api key sent in the authorization header like this:

        let params: [String: AnyObject] = ["email_address": email, "status": "subscribed"]

    guard let url = "https://us10.api.mailchimp.com/3.0/lists/<listID>/members/".stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) else { return }

    let credentialData = "user:<apikey>".dataUsingEncoding(NSUTF8StringEncoding)!
    let base64Credentials = credentialData.base64EncodedStringWithOptions([])

    let headers = ["Authorization": "Basic \(base64Credentials)"]

    Alamofire.request(.POST, url, headers: headers, parameters: params, encoding: .URL)
        .responseJSON { response in

        if response.result.isFailure {

        }
        else if let responseJSON = response.result.value as? [String: AnyObject] {

        }
    }

edit: See Derek Soike's answer below for Swift 3

Abbey Jackson
  • 885
  • 10
  • 20
  • I am using Amalmofire 4.2.0 to send .post request to subscribe new user. .get request works fine and i can get existing user data, but have problem with .pos, i allways get back error:JSONParseError We encountered an unspecified JSON parsing error. This error means that your JSON was formatted incorrectly or was considered invalid or incomplete. -I already posted question but cannot get solution on this.. – MOzeb Dec 27 '16 at 13:58
  • @MOzebek I'm sorry but I don't know Alamofire well enough to help – Abbey Jackson Dec 28 '16 at 19:39
0

If you are passing the apikey as like bxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5dxf-us10, then you'll get the error as you specified.

Try to pass the apikey by skipping the characters after the hyphen (like "bxxxxxxxxxxxxxxxxxxxxxxxxxxxxx5dxf") and check if it works.

Mûhámmàd Yäsår K
  • 1,492
  • 11
  • 24
0

Swift 3 As of Sept. 5, 2017

It says method is an extra argument by accident. It's likely that your encoding part is off. It should look like this:

encoding: JSONEncoding.default

BennyTheNerd
  • 3,930
  • 1
  • 21
  • 16