How to pass parameter to a post API in swift - json

I have a API with the parameters as given in the image.
How to give these parameters in the swift code.
I have tried the code this way, but it does not seem to work.
let header: HTTPHeaders = ["Content-Type":"application/json","x-token": self.usertoken!]
let parameters = [ "request_type" : "nanny_submit_exam",
"exam_id": self.examid!] as [String : Any]
AF.upload(multipartFormData: { (multipartFormData) in
for (key, value) in parameters {
multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
}
for i in 0..<(self.listData?.nanniBookingDetails.questionsData.count)!
{
multipartFormData.append(self.answers[i].data(using: String.Encoding.utf8)!, withName: "answers[i][\(1)]['answer']")
}
}, to: mainURL+URLS.custom.rawValue, usingThreshold: UInt64.init(), method: .post, headers: header).responseJSON { response in
switch response.result {
case .success(let json):
print("Validation Successful",json)
if let res = json as? [String: Any]{
}
case let .failure(error):
// self.loadingview.isHidden = true
print(error)
self.showAlert(message: "No internet connection")
}
}
This is throwing alamofire error Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(error: Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.})) which means the parameter passed is wrong.
Could you tell me where i am wrong with these parameters.As it is working in the postman.

Select "Code" below the save button, you can select swift. This will give you the collection you need to pass as parameter

Related

Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed

I'm trying to decode json from google drive attachment but it shows the following error:
responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(error: Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}))
The JSON:
{
"price" : 5000,
"item" : "Some item"
}
Models:
struct Things: Codable {
let price: Int,
let item: String
}
Request:
Alamofire.request("https://drive.google.com/linkhere").responseJSON { (response) in
switch response.result {
case .failure(let error):
print("error : \(error)")
case .success:
print("success!")
let decoder = JSONDecoder()
let things = try! decoder.decode(Things.self, from: response.data!)
print("things.price : \(things.price)")
print("things.item : \(things.item)")
}
}
This only occurs when i fetch json from google drive attachment (the json is valid).
Are there any difference when fetching json from google drive attachment?
If your response goes in failure case that means api call is having an issue, if your response goes in success state that means it may chances your decoding have some issue.
Failure case:
Check api in postman
Check api method(i.e GET or POST)
Check encoding or content type "application/json"

JSONSerialization with URLSession.shared.dataTask errors

As a part of teaching myself Swift, I am working on a Weather App. I am currently attempting to integrate weather alerts. I use a struct called AlertData to initialize data returned from the API call to weather.gov after serializing the returned data from an API call. Or, at least that is the plan. I have modeled my classes off of other classes that request data from weather.gov, but to get an alert, I need to be able to send variable parameters in my dataTask. I use the URL extension from Apple's App Development with Swift (code below) and have the code set to issue the parameters with the users current location to get alerts where the user is currently.
My problem comes when I attempt to construct the API call to weather.gov in my AlertDataController class(code below). Xcode keeps throwing different errors and I am not sure why. I would like to use a guard statement as I have in my code below, but that throws an error of "Cannot force unwrap value of non-optional type '[[String : Any]]'" in my code where shown. It also throws the same error when I make it a simple constant assignment after unwrapping as the extension returns an optional URL.
The same code works flawlessly when I construct the URL from a string in the guard statement directly as in:
guard let url = URL(string: (baseURL + locationString + stations)) else {
What am I missing? Where my error is thrown is inside the dataTask, and regardless of how it got there, the variable url is an unwrapped URL. Thanks in advance.
Controller class:
import Foundation
import CoreLocation
struct AlertDataController {
func checkWxAlert(location: CLLocation, completion: #escaping (AlertData?) -> Void) {
let baseURL = URL(string: "https://api.weather.gov/alert")!
let locationString = "\(location.coordinate.latitude),\(location.coordinate.longitude)"
var query = [
"active": "1",
"point": locationString
]
guard let url = baseURL.withQueries(query) else {
completion(nil)
print("Unable to build URL in AlertDataController.checkWxAlert with supplied queries.")
return
}
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if let data = data,
let rawJSON = try? JSONSerialization.jsonObject(with: data),
let json = rawJSON as? [String: Any],
let featuresDict = json["features"] as? [[String: Any]],
let propertiesArray = featuresDict!["properties"] as? [String: Any] {
Error: Cannot force unwrap value of non-optional type '[[String : Any]]'
let alertData = AlertData(json: propertiesArray)
completion(alertData)
} else {
print("Either no data was returned in AlertDataController.checkWxAlert, or data was not serialized.")
completion(nil)
return
}
}
task.resume()
}
}
URL extension:
import Foundation
extension URL {
func withQueries(_ queries: [String: String]) -> URL? {
var components = URLComponents(url: self, resolvingAgainstBaseURL: true)
components?.queryItems = queries.flatMap { URLQueryItem(name: $0.0, value: $0.1) }
return components?.url
}
func withHTTPS() -> URL? {
var components = URLComponents(url: self, resolvingAgainstBaseURL: true)
components?.scheme = "https"
return components?.url
}
}
If featuresDict is really an array, you cannot use featuresDict["properties"] syntax. That subscript with string syntax is only for dictionaries. But you've apparently got an array of dictionaries.
You could iterate through the featuresDict array (which I'll rename to featuresArray to avoid confusion), you could do that after you finish unwrapping it. Or, if just want an array of the values associated with the properties key for each of those dictionaries, then flatMap is probably a good choice.
For example:
let task = URLSession.shared.dataTask(with: url) { data, _, error in
guard let data = data,
error == nil,
let json = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any],
let featuresArray = json["features"] as? [[String: Any]] else {
print("Either no data was returned in AlertDataController.checkWxAlert, or data was not serialized.")
completion(nil)
return
}
let propertiesArray = featuresArray.flatMap { $0["properties"] }
let alertData = AlertData(json: propertiesArray)
completion(alertData)
}
Or, if AlertData is expecting each of those properties to be, themselves, a dictionary, you might do:
let propertiesArray = featuresArray.flatMap { $0["properties"] as? [String: Any] }
Just replace that cast with whatever type your AlertData is expecting in its array, json.
Or, if you're only interested in the first property, you'd use first rather than flatMap.
The error
Cannot force unwrap value of non-optional type '[[String : Any]]'
is very clear. It occurs because in the optional binding expression featuresDict is already unwrapped when the next condition is evaluated.
Just remove the exclamation mark
... let propertiesArray = featuresDict["properties"] as? [String: Any] {
The error is not related at all to the way the URL is created.

JSON_encode for ALAMOFIRE

I have a very simple Swift code to retrieve JSON data. But somehow it doesn't work properly.
Alamofire.request("*URL*").validate().responseJSON { response in
print(response.result.value)
if response.result.isSuccess {
if let userList:[[String:Any]] = response.result.value as? [[String:Any]] {
for user:[String:Any] in userList {
if let userName = user["name"] as? String {
self._myList.append(User(name: userName, value: true))
}
}
}
self.tableView.reloadData()
} else {
print(response.result.error)
}
}
During the execution, I get this error message in the console :
Optional(Alamofire.AFError.responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.})))
The print after calling Alamofire.request is showing "nil" in the console.
What I don't understand is it's working if I use .responseString instead of .responseJSON (but it shows only a String). I really need to use .responseJSON as I need to parse the result.
My JSON that appears on the web browser is very simple as well :
[{"name":"MrX","value":"0"}]
Any idea ?
Mika.
use this
import Alamofire
import SwiftyJSON
let baseURL: String = "http://baseURL.com"
Alamofire.request(baseURL)
.responseJSON { response in
guard response.result.error == nil else {
// got an error in getting the data, need to handle it
print("error calling GET")
print(response.result.error!)
return
}
if let value = response.result.value {
let json = JSON(value) // JSON comes from SwiftyJSON
print(json) // to see the JSON response
let userName = json["name"].array // .array comes from SwiftyJSON
for items in userName! {
self._myList.append(User(name: items, value: true))
}
DispatchQueue.main.async {
self.tableView?.reloadData()
}
}
}
and take the .validate() out, if you take that out you will see more detailed error description. Hope that helps.

Alamofire Mailchimp API 3.0 subscribe

I am trying to subscribe new user to Mailchimp list using Alamofire.
Problem starts when I'm trying to subscribe new user with .post method and JSONObject as a parameter:
func subscribeMail(){
let credentialData = "<my_api_key>".data(using: String.Encoding.utf8)!
let base64Credentials = credentialData.base64EncodedString(options: [])
let headers = ["Authorization": "Basic \(base64Credentials)"]
let url = "https://us11.api.mailchimp.com/3.0/lists/<my_list_id>/members/"
let jsonObj: [String: AnyObject] = [
"mail_address" : "testMailAddress#gmail.com" as AnyObject,
"status" : "subscribed" as AnyObject,
]
let valid = JSONSerialization.isValidJSONObject(jsonObj)
print(valid)
Alamofire.request(url, method: .post, parameters: jsonObj , encoding: URLEncoding.default , headers: headers).responseJSON{response in
if response.result.isFailure {
print("Failed")
}
else if (response.result.value as? [String: AnyObject]) != nil {
print(response)
}
}
}
I get back status code 400:
SUCCESS: {
detail = "We encountered an unspecified JSON parsing error.";
instance = "";
status = 400;
title = "JSON Parse Error";
type = "http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/";
}
In Mailchimp documentation:
JSONParseError
We encountered an unspecified JSON parsing error.
This error means that your JSON was formatted incorrectly or was considered invalid or incomplete.
As you can see I am checking my jsonObj if its valid. So I dont get this parsing error..
In Mailchimp API 3.0 its written that just email_address and status fields are needed to subscribe new mail.
If I try to to send request with Alamofire using .get method with some mail address that is already subscribed, everything works fine, I can receive all data from Mailchimp.
Is there really problem with my jsonObj or is it somewhere else?
Change the object key from 'mail_address' to 'email_address' and give a try.
let jsonObj: [String: AnyObject] = [
"email_address" : "testMailAddress#gmail.com" as AnyObject,
"status" : "subscribed" as AnyObject,
]
Since you're getting a JSONParseError, your issue is related to the format in which you're sending the parameters.
Try encoding: JSONEncoding.default instead of encoding: URLEncoding.default.

Invalid type in JSON write (_SwiftValue) using Alamofire

I have tried a lot of things now and are still getting:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (_SwiftValue)'
UPDATE:
I scan a barcode and save the info:
let calendar = Calendar.current
let expiryDate = (calendar as NSCalendar).date(byAdding: .month, value: 3, to: Date(), options: [])?.description
let barcode = BarcodeData(barcodeValue: value,
datetime: dateTime,
expiryDate: expiryDate!,
latitude: latitude.description,
longitude: longitude.description,
status: txtStatus.text!,
type: txtType.text!,
extraText: "")
Object are then mapped to a JSON string, it seems that the slashes (/) are added by this function:
let jsonBarcode = Mapper<BarcodeData>().toJSONString(barcode)
The barcode are then added to a list of String:
barcodeDataList.append(jsonBarcode)
When I click a button I invoke the web service, that anticipate parameters in the form of:
let testParams : Parameters =
[ "udid": "my_udid",
"data": jsonArray
]
jsonArray consist of an array of the BarcodeData-object(s) as seen above.
Communication with the web service looks like:
Alamofire.request(url, method: .post, parameters: testParams, encoding: JSONEncoding.default).validate().responseJSON { response in
switch response.result {
case .success:
print("Validation successful")
if let json = response.result.value {
print("JSON: \(json)")
}
case .failure(let error):
print("Error: \(error)")
}
}
The following is passed to the ws:
["udid": "\"001-my_udid\"", "data": [
"{\"latitude\":\"0.0\",\"status\":\"Empty\",\"datetime\":\"2016-09-20 05:10\",\"longitude\":\"0.0\",\"type\":\"ABC123\",\"barcodevalue\":\"123456\"}"
]]
The json array for "data" validates at jsonlint.com and the response from the server is in the form of a json object like:
{result: "Data successfully received"}
Change your encoding in request from encoding: JSONEncoding.default to encoding: URLEncoding.default
I think you need to encode your array in json object try something like this
do{
let data = try NSJSONSerialization.dataWithJSONObject(mappingArray, options: NSJSONWritingOptions(rawValue: 0))
let mappedString : String = (String(data: data , encoding: NSUTF8StringEncoding)!)
return mappedString
}
catch{
print(error)
return error as! String
}
Append this string with your url