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"
Related
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
I'm pretty sure my model is correct based on my data, I cannot figure out why I am getting the format error?
JSON:
{
"1596193200":{
"clientref":1,
"type":"breakfast"
},
"1596200400":{
"clientref":0,
"type":"lunch"
},
"1596218400":{
"clientref":2,
"type":"dinner"
}
}
model:
struct Call: Decodable {
let clientref: Int?
let type: String?
}
edit updated question with the code for decoding the json data from the URL:
class CallService {
static let shared = CallService()
let CALLS_URL = "url.com/Calls.json"
func fetchCalls(completion: #escaping ([Call]) -> ()) {
guard let url = URL(string: CALLS_URL) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
// handle error
if let error = error {
print("Failed to fetch data with error: ", error.localizedDescription)
return
}
guard let data = data else {return}
do {
let call = try JSONDecoder().decode([Call].self, from: data)
completion(call)
} catch let error {
print("Failed to create JSON with error: ", error.localizedDescription)
}
}.resume()
}
}
I strongly suggest to learn how to debug: it includes where to look, what info to get, where to get them, etc, and at the end, fix it.
That's a good thing that you print the error, most beginner don't.
print("Failed to create JSON with error: ", error.localizedDescription)
=>
print("Failed to create JSON with error: ", error)
You'll get a better idea.
Second, if it failed, print the data stringified. You're supposed to have JSON, that's right. But how often do I see question about that issue, when it fact, the answer wasn't JSON at all (the API never stated it will return JSON), the author were facing an error (custom 404, etc.) and did get a XML/HTML message error etc.
So, when the parsing fails, I suggest to do:
print("Failed with data: \(String(data: data, encoding: .utf8))")
Check that the output is a valid JSON (plenty of online validators or apps that do that).
Now:
I'm pretty sure my model is correct based on my data,
Well, yes and no.
Little tip with Codable when debuting (and not using nested stuff): Do the reverse.
Make your struct Codable if it's not the case yet (I used Playgrounds)
struct Call: Codable {
let clientref: Int?
let type: String?
}
do {
let calls: [Call] = [Call(clientref: 1, type: "breakfast"),
Call(clientref: 0, type: "lunch"),
Call(clientref: 2, type: "dinner")]
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted]
let jsonData = try encoder.encode(calls)
let jsonStringified = String(data: jsonData, encoding: .utf8)
if let string = jsonStringified {
print(string)
}
} catch {
print("Got error: \(error)")
}
Output:
[
{
"clientref" : 1,
"type" : "breakfast"
},
{
"clientref" : 0,
"type" : "lunch"
},
{
"clientref" : 2,
"type" : "dinner"
}
]
It doesn't look like. I could only used an array to put various calls inside a single variable, and that's what you meant for decoding, because you wrote [Call].self, so you were expecting an array of Call. We are missing the "1596218400" parts. Wait, could it be a dictionary at top level? Yes. You can see the {} and the fact it uses "keys", not listing one after the others...
Wait, but now that we printed the full error, does it make more sense now?
typeMismatch(Swift.Array<Any>,
Swift.DecodingError.Context(codingPath: [],
debugDescription: "Expected to decode Array<Any> but found a dictionary instead.",
underlyingError: nil))
Fix:
let dictionary = try JSONDecoder().decode([String: Call].self, from: data)
completion(dictionary.values) //since I guess you only want the Call objects, not the keys with the numbers.
From the code you provided it looks like you are trying to decode an Array<Call>, but in the JSON the data is formatted as a Dictionary<String: Call>.
You should try:
let call = try JsonDecoder().decode(Dictionary<String: Call>.self, from: data)
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.
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
Been working on this for a bit with no success. I have a function that goes to a UIButton solely to perform alamofire calls to my rails api which uses all JSON.
I'm using Swift 2, Alamofire 3, XCode 7 & Rails 4 for my api which is deployed to Heroku
I keep getting this error when I fire off the function :
alamofire.error Code=-6006 "JSON could not be serialized. Input data was nil or zero length.
Here is my code :
#IBAction func Save(sender: AnyObject) {
let postsEndpoint: String = "https://APIURL"
let parameters = [
"users": [
"name": "James McHarty",
"avatar": "Some binary data",
"post": [
"title": "First Test Post",
"body": "This is the first test post for the API",
"liked": "8", //will make INT later
"img": "more binary data"
]
]
]
Alamofire.request(.POST, postsEndpoint, parameters: parameters, encoding: .JSON)
.responseJSON { response in
guard response.result.error == nil else {
// got an error in getting the data, need to handle it
print(response.result.error!)
return
}
}
print("func'd")
}
This is not Alamofire or swift error, The response returned by the server is not in the JSON format. you can print out response data and check what is wrong in this.
try this code to print out our server data to easily identifying to error and resolve this.
Alamofire.request("Your url").responseJSON(completionHandler: { (response) in
switch response.result {
case .success(let value):
break
case .failure(let error):
print("\n\n===========Error===========")
print("Error Code: \(error._code)")
print("Error Messsage: \(error.localizedDescription)")
if let data = response.data, let str = String(data: data, encoding: String.Encoding.utf8){
print("Server Error: " + str)
}
debugPrint(error as Any)
print("===========================\n\n")
}
})
The response returned by the server is not in the JSON format. You can use the tool to test the request first.
Print out of the error code is not a HTTP error code, because of the failure to resolve JSON
You need to check the mimeType it will be "text/plain" instead of "application/json". That's why JSONSerialization class not able to parse the data.