How to make Swift JSON request params - json

I got a problem with making a request to a server, I got a parsing error, could you help me to make the request properly?
I need to make a request like this:
"{ \"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"call\", \"params\": [ \"c36c5a835cf88e82f97dcfa5b74f53f4\",\"network.interface.wan\",\"status\", {} ] }"
My request:
["jsonrpc": "2.0", "id": 1, "method": "call", "params": [token, "network.interface.wan", "status", []]]

If you want to convert Dictionary as JSON String response then you can try like this way.
Edit: In JSON string with params array the last object is empty dictionary so you need to set last object of params array as [:] instead of []
let dic:[String:Any] = [
"jsonrpc": "2.0",
"id": 1,
"method": "call",
"params": [
"token",
"network.interface.wan",
"status", [:]
]
]
if let data = try? JSONSerialization.data(withJSONObject: dic),
let string = String(data: data, encoding: .utf8){
print(string)
}
Output
{\"method\":\"call\",\"jsonrpc\":\"2.0\",\"id\":1,\"params\":[\"token\",\"network.interface.wan\",\"status\",{}]}

Related

Swift JSONEncoding problem with encoding a list of dictionaries

I am having problems with sending a list of dictionaries as the value for one of my keys in a dictionary. I'm sending a dictionary that represents a game, with one of the key value pairs being a list of points. So for my 'points' key the corresponding value is a list of dictionaries.
var allPoints : [[String: String] = []
for playerScoreTracker in playerScoreTrackers!{
for point in playerScoreTracker.points{
let tempDict : [String : String] = ["type": point.typeOfPoint.rawValue, "scorer" : point.scorer.uuid]
allPoints.append(tempDict)
}
}
var parameters : Dictionary<String, Any> = [
"playerOne": playerOne.uuid,
...
"team_two_score": scoreboard.teamTwoScore,
"confirmed": false,
"points": allPoints
]
The problem is that when I send this dictionary using Alamofire (which uses JSONEncoding.default to my knowledge) it ends up sending something different than I want. My Alamofire send function looks like this
static func post<T: Decodable>(url: String, parameters: [String: Any], returnType: T.Type, completion: #escaping (Bool, Any) -> Void) {
AF.request(url, method: .post, parameters: parameters, headers: getHeaders()).responseDecodable(of: returnType.self) { response in
guard let returnStatusCode = response.response?.statusCode else {
let returnData : [String] = ["No connection."]
completion(false, returnData)
return
}
switch returnStatusCode {
case 200, 201:
let returnData = response.value!
completion(true, returnData)
case 400:
var errorsDict : [String: [String]] = [:]
do {
errorsDict = try JSONDecoder().decode(Dictionary<String, [String]>.self, from: response.data!)
} catch {
errorsDict["my_side_errors"] = ["Couldn't decode json response."]
}
let errors : [String] = getErrorsFromParams(params: parameters, errorsDict: errorsDict)
completion(false, errors)
default:
let errors : [String] = ["Error."]
completion(false, errors)
}
}
}
For some reason when it encodes my parameters it sends them like this...
{
'confirmed': ['0'],
'playerFour': ['8b52d186-ab60-438e-92f1-a3d35430ea81'],
'playerOne': ['f33e09b5-be8b-49e7-99c2-1e2df7512a71'],
'playerThree': ['583e0143-7352-4907-a806-a3b16baceefc'],
'playerTwo': ['24da0653-7fbc-41c3-8a47-bdefb9323eb2'],
'points[][type]': ['tk', 'tk'],
'points[][scorer]': ['8b52d186-ab60-438e-92f1-a3d35430ea81', '8b52d186-ab60-438e-92f1-a3d35430ea81'],
'team_one_score': ['12'],
'team_two_score': ['0'],
'time_ended': ['2021-09-11 10:54:00'],
'time_started': ['2021-09-11 10:53:57']
}
The list of dictionaries I send as points is being split up into two lists, one list for each key in the array.
If I send the same JSON in Postman, it works fine and exactly how I want it to. This is the JSON I send it in Postman...
{
"playerOne": "f33e09b5-be8b-49e7-99c2-1e2df7512a71",
"playerTwo": "99028402-abdd-42dd-a8d9-48c05ba2787e",
"type": "pu",
"team_two_score": 0,
"time_started": "2021-09-11 12:33:44",
"time_ended": "2021-09-11 12:33:48",
"points": [
{"scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71", "type": "tk"},
{"scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71", "type": "tk"},
{"type": "tk", "scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71"},
{"type": "tk", "scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71"},
{"type": "tk", "scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71"},
{"scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71", "type": "tk"}
],
"playerThree": "24da0653-7fbc-41c3-8a47-bdefb9323eb2",
"playerFour": "583e0143-7352-4907-a806-a3b16baceefc",
"team_one_score": 12,
"confirmed": false
}
This JSON being sent works fine with my backend. I cannot for the life of me figure out how to get Swift to encode my params in this way.
Here's a printout of the parameters right before I send them.
params: [
"team_one_score": 13,
"points": [
["type": "tk", "scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71"],
["scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71", "type": "tk"],
["type": "tk", "scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71"],
["type": "tk", "scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71"],
["type": "tk", "scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71"],
["scorer": "f33e09b5-be8b-49e7-99c2-1e2df7512a71", "type": "sk"]
],
"time_started": "2021-09-11 12:12:26",
"confirmed": false,
"time_ended": "2021-09-11 12:12:30",
"playerThree": "583e0143-7352-4907-a806-a3b16baceefc",
"team_two_score": 0,
"playerTwo": "24da0653-7fbc-41c3-8a47-bdefb9323eb2",
"playerFour": "8b52d186-ab60-438e-92f1-a3d35430ea81",
"playerOne": "f33e09b5-be8b-49e7-99c2-1e2df7512a71"
]
Here's the output from cURLDescription
$ curl -v \
-X POST \
-H "User-Agent: DayOfDie/1.0 (aberard.DayOfDie; build:1; iOS 14.5.0) Alamofire/5.4.1" \
-H "Accept-Encoding: br;q=1.0, gzip;q=0.9, deflate;q=0.8" \
-H "Accept-Language: en;q=1.0" \
-H "Authorization: Token be1d6e220931d0249e3d600ef9682909f39252ec" \
-H "Content-Type: application/x-www-form-urlencoded; charset=utf-8" \
-d "confirmed=0&playerFour=8b52d186-ab60-438e-92f1-a3d35430ea81&playerOne=f33e09b5-be8b-49e7-99c2-1e2df7512a71&playerThree=583e0143-7352-4907-a806-a3b16baceefc&playerTwo=24da0653-7fbc-41c3-8a47-bdefb9323eb2&points%5B%5D%5Btype%5D=sk&points%5B%5D%5Bscorer%5D=f33e09b5-be8b-49e7-99c2-1e2df7512a71&points%5B%5D%5Btype%5D=tk&points%5B%5D%5Bscorer%5D=f33e09b5-be8b-49e7-99c2-1e2df7512a71&points%5B%5D%5Btype%5D=tk&points%5B%5D%5Bscorer%5D=f33e09b5-be8b-49e7-99c2-1e2df7512a71&points%5B%5D%5Bscorer%5D=f33e09b5-be8b-49e7-99c2-1e2df7512a71&points%5B%5D%5Btype%5D=tk&points%5B%5D%5Bscorer%5D=f33e09b5-be8b-49e7-99c2-1e2df7512a71&points%5B%5D%5Btype%5D=tk&team_one_score=11&team_two_score=0&time_ended=2021-09-11%2012%3A18%3A55&time_started=2021-09-11%2012%3A18%3A51" \
"http://127.0.0.1:8000/games/"
Larme figured it out. For some reason or another my alamofire request was encoding it using url encoding instead of json encoding. I just added "encoding: JSONEncoding.default" to my request params and everything works fine now.

Convert Dictionary to JSON Swift

I am new to the iOS development , I have dictionary as given below, I want to convert it to JSON, pass it to API
["checkinDate": "",
"data": [{
"abc": 2,
"cde": 13,
"edt": 1,
"shortName": "OCC"
}],
"incidentDescription": "",
"store": "ABD"
]
Code:
let jsonData = try! JSONSerialization.data(withJSONObject: saveDict)
let jsonString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue)
I have used below code but it is giving output as
"materialList": ["{\"abc\":2,\"cde\":13,\"edt\":1,\"shortName\":\"OCC\"}"],
"checkinDate": "",
"incidentDescription": "",
It is add \ while converting array of dictionary to JSON

"Incorrect JSON format"

I am making a POST request with required body parameters, testing this POST request in POSTMAN gives me correct response, but when I am passing same body parameters from my code I am getting below error-:
Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.
Code -:
func submitStudentAttendance(url:String,id:String,SessionID: Int,SchoolID:Int,BatchID:Int,ClassID:Int,SectionID:Int,Medium:Int,Date:String,accessToken:String) {
let params : [String:Any] = [
"$id":"1",
"SchoolID":1,
"SessionID":42,
"BatchID":106,
"ClassID":634,
"SectionID":1246,
"Medium":"English",
"Date":"0001-01-01T00:00:00",
"CreatedBy":118,
"CreatedOn":"2019-04-14T17:02:34",
"studentList":"",
"AttendenceData":"[{\"ID\":0,\"SchoolID\":null,\"SessionID\":null,\"ClassID\":634,\"SectionID\":1246,\"StudID\":\"DSM00399\",\"SubjectID\":null,\"Date\":\"0001-01-01T00:00:00\",\"Attendence\":\"P\",\"CreatedOn\":null,\"CreatedBy\":0,\"IsActive\":null,\"Remarks\":\"rem16\",\"timeID\":null,\"AtndType\":null,\"BatchID\":null,\"Medium\":null}]"
]
let urlRequest = NSURL(string: url)
var request = URLRequest(url: urlRequest! as URL)
let tokenString = "Bearer " + accessToken
request.httpMethod = "POST"
request.setValue(tokenString, forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let data = try! JSONSerialization.data(withJSONObject: params, options: [])
let json = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
if let json = json {
print(json)
}
request.httpBody = json!.data(using: String.Encoding.utf8.rawValue);
let alamoRequest = Alamofire.request(request as URLRequestConvertible)
alamoRequest.responseString {
response in
switch response.result {
case .success:
if response.data != nil {
do{
let json = try JSON(data: response.data!)
print(json)
}catch{
print(error)
}
}
break
case .failure(let error):
print(error)
}
}
}
The body part is exactly same as in POSTMAN, but still not working. Can anyone let me know what's going wrong here? Is this server side issue or I am sending body request in wrong format?
POSTMAN RESPONSE -:
When the params as declared in your question is converted into JSON, it looks like this. Here, AttendanceData value is not converted as proper JSON structure. It looks like a string.
JSON from your param:
{
"Date": "0001-01-01T00:00:00",
"CreatedBy": 118,
"$id": "1",
"BatchID": 106,
"ClassID": 634,
"Medium": "English",
"studentList": "",
"SchoolID": 1,
"SectionID": 1246,
"AttendenceData": "[{\"ID\":0,\"SchoolID\":null,\"SessionID\":null,\"ClassID\":634,\"SectionID\":1246,\"StudID\":\"DSM00399\",\"SubjectID\":null,\"Date\":\"0001-01-01T00:00:00\",\"Attendence\":\"P\",\"CreatedOn\":null,\"CreatedBy\":0,\"IsActive\":null,\"Remarks\":\"rem16\",\"timeID\":null,\"AtndType\":null,\"BatchID\":null,\"Medium\":null}]",
"CreatedOn": "2019-04-14T17:02:34",
"SessionID": 42
}
But if you declare param as shown below, and converted to JSON, AttendanceData value is properly converted to JSON.
let params : [String:Any] = [
"$id":"1",
"SchoolID":1,
"SessionID":42,
"BatchID":106,
"ClassID":634,
"SectionID":1246,
"Medium":"English",
"Date":"0001-01-01T00:00:00",
"CreatedBy":118,
"CreatedOn":"2019-04-14T17:02:34",
"studentList":"",
"AttendenceData":[
"ID":0,"SchoolID":"null","SessionID":"null","ClassID":634,"SectionID":1246,"StudID":"DSM00399","SubjectID":"null","Date":"0001-01-01T00:00:00","Attendence":"P","CreatedOn":"null","CreatedBy":0,"IsActive":"null","Remarks":"rem16","timeID":"null","AtndType":"null","BatchID":"null","Medium":"null"
]
]
JSON
{
"$id": "1",
"BatchID": 106,
"CreatedBy": 118,
"ClassID": 634,
"studentList": "",
"SectionID": 1246,
"SessionID": 42,
"AttendenceData": {
"IsActive": "null",
"AtndType": "null",
"SectionID": 1246,
"timeID": "null",
"SessionID": "null",
"Attendence": "P",
"Date": "0001-01-01T00:00:00",
"Remarks": "rem16",
"Medium": "null",
"SchoolID": "null",
"BatchID": "null",
"ClassID": 634,
"StudID": "DSM00399",
"SubjectID": "null",
"CreatedBy": 0,
"ID": 0,
"CreatedOn": "null"
},
"Date": "0001-01-01T00:00:00",
"CreatedOn": "2019-04-14T17:02:34",
"Medium": "English",
"SchoolID": 1
}
Hope it could also solve your problem.

Parsing JSON response in Swift 3

I've got an API endpoint that returns JSON in the following format:
[
{
"id": "1",
"name": "John"
},
{
"id": "2",
"name": "Jane"
},
{
"id": "3",
"name": "Nick"
}
]
I am trying to parse this in Swift 3, but I can only find examples to parse JSON formatted like so:
{
"blogs": [
{
"needspassword": true,
"id": 73,
"url": "http://remote.bloxus.com/",
"name": "Bloxus test"
},
{
"needspassword": false,
"id": 74,
"url": "http://flickrtest1.userland.com/",
"name": "Manila Test"
}
],
"stat": "ok"
}
, which has an extra level above what mine does.
So, where examples I've seen are simply parsing their data like jsonResponse["blogs"], I can't do that as my format is different.
How can I parse the format I've got, or how can I return a format that is easier to parse?
Any suggestions appreciated, thanks!
You can just do the following :
let data = // Data received from WS
do {
let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions()) as? [[String : String]]
//json is now an array from dictionary matching your model
}
catch {
//handle error
}
This will parse it when placed in the network call.
do {
let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions()) as! [[String : AnyObject]]
let firstPerson = json[0]
print(firstPerson)
let id = firstPerson["id"] as! String
print(id)
let name = firstPerson["name"] as! String
print(name)
} catch {
//handle error
}
Also, I tend to be against advising third party libraries, but SwiftyJSON is an exception I make. If you want to try it, add this to your pod file:
pod SwiftyJSON', '3.0.0'
Documentation: https://github.com/SwiftyJSON/SwiftyJSON
EDIT - Answering Comment:
Replacement line:
if let id = firstPerson["id"] as? String {
print(id)
}
Replacement line (if you need to hold on to the value):
var thisId: String?
if let id = firstPerson["id"] as? String {
thisId = id
}
print(thisId ?? "")
i don't really know swift but there might be the equivalent of ajax json encoding (server side you json_encode your array and client side you json_decode the response)
the idea is to have the same formatter that encodes and decodes the data

(Swift) twilio post request to set attributes using alamofire

I am attempting to use Twilio's REST Api and Alamofire to set certain Attributes to a Channel when creating it (https://www.twilio.com/docs/api/ip-messaging/rest/channels#action-create)
let parameters : [String : AnyObject] = [
"FriendlyName": "foo",
"UniqueName": "bar",
"Attributes": [
"foo": "bar",
"bar": "foo"
],
"Type": "private"
]
Alamofire.request(.POST, "https://ip-messaging.twilio.com/v1/Services/\(instanceSID)/Channels", parameters: parameters)
.authenticate(user: user, password: password)
.responseJSON { response in
let response = String(response.result.value)
print(response)
}
Using that code, the response I received back was that a Channel was created with FriendlyName foo and UniqueName bar, but that Channel had no Attributes set.
Looking at the Alamofire github (https://github.com/Alamofire/Alamofire) I see that there's a way to send a POST Request with JSON-encoded Parameters. So I tried this:
let parameters : [String : AnyObject] = [
"FriendlyName": "foo",
"UniqueName": "bar15",
"Attributes": [
"foo": "bar",
"bar": "foo"
],
"Type": "private"
]
Alamofire.request(.POST, "https://ip-messaging.twilio.com/v1/Services/\(instanceSID)/Channels", parameters: parameters, encoding: .JSON)
.authenticate(user: user, password: password)
.responseJSON { response in
let response = String(response.result.value)
print(response)
}
When adding "encoding: .JSON" to the request the response shows that not only were the Attributes not set but also the FriendlyName and UniqueName were nil, unlike before when they were correctly set using the URL-Encoded Parameters.
Am I setting the Attributes wrong in 'parameters'? Twilio's documentation says that Attributes is "An optional metadata field you can use to store any data you wish. No processing or validation is done on this field."
Help would be appreciated :)
I have figured out an answer to my question. Turns out I had formatted the Attributes field incorrectly.
Here is the code that worked for me:
let parameters : [String : AnyObject] = [
"FriendlyName": "foo",
"UniqueName": "bar",
"Attributes": "{\"key\":\"value\",\"foo\":\"bar\"}",
"Type": "private"
]
Alamofire.request(.POST, "https://ip-messaging.twilio.com/v1/Services/\(instanceSID)/Channels/", parameters: parameters)
.authenticate(user: user, password: password)
.responseJSON { response in
let response = String(response.result.value)
print(response)
debugPrint(response)
}
Hope this helps others :)