'API Key Missing' when making Mailchimp API call from Swift 5 iOS App - ios

I am trying to add a subscriber to my mailing list from my Swift 5 iOS app. I am seeing the following error when trying to do this:
{
detail = "Your request did not include an API key.";
instance = "3f4cb654-c674-4a97-adb8-b4eb6d86053a";
status = 401;
title = "API Key Missing";
type = "http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/";
}
Of course this indicates that I am missing my API Key, however I am specifying it in the Authorization header (see below code). I have tried a mix of the answer here and the guide here but I'm not having much luck so far. Here's my current code for setting up the request:
let mailchimpAPIURL = "https://us3.api.mailchimp.com/3.0"
let requestURL = NSURL(string: mailchimpAPIURL)!
let apiCredentials = "anystring:<API_KEY>"
let loginData = apiCredentials.data(using: String.Encoding.utf8)!.base64EncodedString()
let params = [
"list_id": "<LIST_ID>",
"email_address": email,
"status": "subscribed",
"merge_vars": [
"FNAME": firstName,
"LNAME": lastName
]
] as [String: Any]
let request = NSMutableURLRequest(url: requestURL as URL)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.setValue("Basic \(loginData)", forHTTPHeaderField: "Authorization")
do {
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: [])
} catch {
return
}

You need to send api key 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] {
}
}

Okay, I got it. #Sam's answer helped me realise that the URL I was using was wrong, and I needed to add the ListID into that URL. I also changed setValue to addValue, and changed NSMutableURLRequest to URLRequest. I also added request.httpMethod = "POST" Here is my updated, working code:
let subscribeUserURL = "https://us3.api.mailchimp.com/3.0/lists/<LISTID>/members/"
let requestURL = NSURL(string: subscribeUserURL)!
let apiCredentials = "anystring:<APIKEY>"
let loginData = apiCredentials.data(using: String.Encoding.utf8)!.base64EncodedString()
let params = [
"email_address": email,
"status": "subscribed",
"merge_fields": [
"FNAME": firstName,
"LNAME": lastName
]
] as [String: Any]
var request = URLRequest(url: requestURL as URL)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("Basic \(loginData)", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
do {
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: [])
} catch {
return
}

Related

Send data to Airtables through a POST request with a json body

Im trying to send data to Airtables using its REST APIs based on the documentation. The part Im stuck is adding the parameters. It throws me an error saying "Invalid request: parameter validation failed. Check your request data".
The Curl according to the doc as bellow.
My partially done code as bellow.
let table_name = "Diet%20Plan"
let base_id = "appmrzybooFj9mFVF"
let token = "SomeID"
// prepare json data
let json: [String: String] = ["Food Type": "Minseee",
"Person Name": "Rabiit Con"]
// create the url with URL
let url = URL(string: "https://api.airtable.com/v0/\(base_id)/\(table_name)")! // change server url accordingly
let jsonData = try? JSONSerialization.data(withJSONObject: json)
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.setValue( "Bearer \(token)", forHTTPHeaderField: "Authorization")
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON) //Code after Successfull POST Request
}
}
task.resume()
}
From your code, request body seems to be made like:
{"Person Name":"Rabiit Con","Food Type":"Minseee"}
What it needs to be sending is:
"fields": {
"Person Name":"Rabiit Con",
"Food Type":"Minseee"
}
Try
let json: [String: Any] = ["fields": ["Food Type": "Minseee",
"Person Name": "Rabiit Con"]]
let jsonData = try? JSONSerialization.data(withJSONObject: json)

Get Method JSON Data to show in Textfield not working (Error)

How to get JSON data in textfield for GET method. My Json data is as follows,
SUCCESS: {"code":200,
"shop_detail":{"name":"dad","address":"556666","city":"cSC","area":"scsc","street":"vddva","building":"jhkj","description":null}
"shop_types":
[{"id":7,"name":"IT\/SOFTWARE","merchant_type":"office",}]}
My code with header and URL is
func getProfileAPI() {
let headers: HTTPHeaders = [
"Authorisation": AuthService.instance.tokenId ?? "",
"Content-Type": "application/json",
"Accept": "application/json"
]
print(headers)
let scriptUrl = "http://haitch.igenuz.com/api/merchant/profile"
if let url = URL(string: scriptUrl) {
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = HTTPMethod.get.rawValue
urlRequest.addValue(AuthService.instance.tokenId ?? "", forHTTPHeaderField: "Authorization")
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
Alamofire.request(urlRequest)
.responseString { response in
debugPrint(response)
print(response)
if let result = response.result.value // getting the json value from the server
{
}
}
After print response I am getting the values of JSON data printed, if I am having textfield like name.text, address.text. I want to show the values as I get through JSON response. If I try below code it fails in Dictionary.
if let data = data {
print(data)
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
let jsonData:NSDictionary = (data as? NSDictionary)!
print(jsonData)
}}
Try this,
struct Root: Codable {
let code: Int
let shopDetail: ShopDetail
let shopTypes: [ShopType]
}
struct ShopDetail: Codable {
let name, address, area, street, building, city: String
}
struct ShopType: Codable {
let name, merchantType: String
}
And Call
func getProfileAPI() {
let headers: HTTPHeaders = [
"Authorisation": AuthService.instance.tokenId ?? "",
"Content-Type": "application/json",
"Accept": "application/json"
]
print(headers)
let scriptUrl = "http://haitch.igenuz.com/api/merchant/profile"
if let url = URL(string: scriptUrl) {
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = HTTPMethod.get.rawValue
urlRequest.addValue(AuthService.instance.tokenId ?? "", forHTTPHeaderField: "Authorization")
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")
Alamofire.request(urlRequest).response { response in
guard
let data = response.data,
let json = String(data: data, encoding: .utf8)
else { return }
print("json:", json)
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let root = try decoder.decode(Root.self, from: data)
print(root)
self.t1.text! = root.shopDetail.name
// self.t3.text! = root.shopDetail.description
print(root.shopDetail.name)
print(root.shopDetail.address)
for shop in root.shopTypes {
self.merchant_Type.text! = shop.merchantType
self.t2.text! = shop.name
print(shop.name)
print(shop.merchantType)
}
} catch {
print(error)
}
}}}

how to make post request with row http body using swift as postman request test?

request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
let httpbody = object.data(using: String.Encoding.utf8)
request.httpBody = httpbody
You can directly generate a code from postman itself. Also, for your reference, you can call post request with row body as given below.
let headers = [
"content-type": "application/json",
"cache-control": "no-cache"
]
let parameters = ["order": ["line_items": [
["variant_id": 18055889387589,
"quantity": 1]
]]] as [String : Any]
let postData = try? JSONSerialization.data(withJSONObject: parameters, options: [])
if let data = postData {
let request = NSMutableURLRequest(url: NSURL(string: "http://")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = data as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error?.localizedDescription ?? "")
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse?.statusCode ?? 0)
let reponseData = String(data: data!, encoding: String.Encoding.utf8)
print("responseData: \(reponseData ?? "Blank Data")")
}
})
dataTask.resume()
}
Let me know if you have any query.
Thanks.

How to send array of dictionarys of JSON in SWIFT - (POST method)

I want to know how I can send more than one array of dictionary in JSON. I have to do POST in this format :
{
"Account":
{
"lastname":"VVV",
"PersonEmail":"vaaaay#gmail.com"
},
"Member":
{
"Password__C":"12345"
},
"ProgramName":"My Chili's"
}
This is what I have done so far:
lname = lastName.text!
fname = firstName.text!
email = emailSignUp.text!
pass = passwordSignup.text!
let signUpDict : [String:Any] =
[
"Account": [
"lastname": lname!,
"PersonEmail": email!
],
"Member": [
"Password__C": pass!
],
"ProgramName": "My Chilli's"
]
var urlRequest = URLRequest(url: URL(string: url)!)
urlRequest.httpMethod = "POST"
urlRequest.setValue("application/json;application/html; charset=utf-8", forHTTPHeaderField: "Content-Type")
urlRequest.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Accept")
do{
let postData = try? JSONSerialization.data(withJSONObject: signUpDict, options: JSONSerialization.WritingOptions.prettyPrinted)
urlRequest.httpBody = postData
}
catch {
print("Couldnt post this")
}
let task = URLSession.shared.dataTask(with:urlRequest as URLRequest){(data,response,error) in
if error != nil{
print("Error is \(error)")
return
}
print("Data Responded : \(data)")
print("response is: \(response)")
}
task.resume()
I am getting a 500 error in response.
{ status code: 500, headers {
"Cache-Control" = "s-maxage=0";
"Content-Security-Policy" = "referrer origin-when-cross-origin";
"Content-Type" = "application/json;charset=UTF-8";
Date = "Tue, 01 Aug 2017 12:19:44 GMT";
"Transfer-Encoding" = Identity;
"X-XSS-Protection" = "1; mode=block";
} })
I think the way I have written the signUpDict could be incorrect or missing something, could someone please guide me through this?
Edit:
As requested I tried the json on POSTMAN, however this is my first time using POSTMAN(complete newbie). So I am not sure if I did it right.
POSTMAN screenshot
Please Try to use this updated code
lname = lastName.text!
fname = firstName.text!
email = emailSignUp.text!
pass = passwordSignup.text!
let signUpDict : [String:Any] =
[
"Account": [
"lastname": lname!,
"PersonEmail": email!
],
"Member": [
"Password__C": pass!
],
"ProgramName": "My Chilli's"
]
let data = try! JSONSerialization.data(withJSONObject: signUpDict, options: JSONSerialization.WritingOptions.prettyPrinted)
let json = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
if let json = json {
print(json)
}
let jsonData = json!.data(using: String.Encoding.utf8.rawValue);
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = HTTPMethod.post.rawValue
request.setValue("application/json; charset=UTF-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData
Replace following line :
From
urlRequest.setValue("application/json;application/html; charset=utf-8", forHTTPHeaderField: "Content-Type")
To
urlRequest.setValue("application/json; charset=UTF-8", forHTTPHeaderField: "Content-Type")
Try This:-
lname = lastName.text!
fname = firstName.text!
email = emailSignUp.text!
pass = passwordSignup.text!
let accountDict = NSMutableDictionary.init()
let memberDict = NSMutableDictionary.init()
let finalDict = NSMutableDictionary.init()
accountDict.setValue(lname, forKey: "lastname")
accountDict.setValue(email, forKey: "PersonEmail")
memberDict.setValue(pass, forKey: "Password__C")
finalDict.setValue(accountDict, forKey: "Account")
finalDict.setValue(memberDict, forKey: "Member")
finalDict.setValue("My Chili's", forKey: "ProgramName")
print(finalDict)
let data = try! JSONSerialization.data(withJSONObject: finalDict, options: JSONSerialization.WritingOptions.prettyPrinted)
let json = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
if let json = json {
print(json)
}
let jsonData = json!.data(using: String.Encoding.utf8.rawValue);
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = HTTPMethod.post.rawValue
request.setValue("application/json; charset=UTF-8", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData

Receive POST request from Swift in Node.js

I am trying to receive and process a POST request being sent from my iOS app to my Node.js web server. The server responds with HTTP Error 502 whenever I try to send this POST request. Could you please look at my code below and see what is wrong with it? Thank you!
Node.js Code
app.post('/applogin', function(req, res) {
var parsedBody = JSON.parse(req.body);
console.log(parsedBody)
});
Swift Code (POST function)
func httpPost(jsonData: Data) {
if !jsonData.isEmpty {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData
URLSession.shared.getAllTasks { (openTasks: [URLSessionTask]) in
NSLog("open tasks: \(openTasks)")
}
let task = URLSession.shared.dataTask(with: request, completionHandler: { (responseData: Data?, response: URLResponse?, error: Error?) in
NSLog("\(response)")
})
task.resume()
}
}
Swift Code (sending of the POST request)
#IBAction func onClick(_ sender: Any) {
let username = Username.text
let password = Password.text
var dataString = "username: \(username), password: \(password)"
let data = dataString.data(using: .utf8)
httpPost(jsonData: data!)
}
Thanks in advance!
You have to send a json instead dataString, and you have to set the "Content Type" header with value "application/json"
Swift 2
let request = NSMutableURLRequest(URL: requestUrl)
request.HTTPMethod = "POST"
let params = ["username" : username, "password" : password] as Dictionary<String, AnyObject>
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options:NSJSONWritingOptions.PrettyPrinted)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
Many answers they don't mention that we need to set header for the request from Swift side before sending to the backend otherwise it'll be a string in a wrong format that we can't use JSON.parse, here's what I firgured out (NOTE the IMPORTANT line):
let json = [
"email": emailTextField.text
]
let jsonData = try! JSONSerialization.data(withJSONObject: json)
let url = URL(string: BASE_URL + "/auth/register")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData
//IMPORTANT
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
}
}
task.resume()
And in your NodeJS with Express just call req.body and you're done
Try this:
app.post('/applogin', function(req, res) {
var parsedBody = JSON.parse(req.body);
console.log(parsedBody)
res.send("Request received")
});

Resources