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.