Reputation: 1056
I am trying to convert my swift struct to json format. There seems to be quite a few questions like this, but none of the solutions has worked for me so far.
Here is my struct
struct Rec : Codable {
var name:String
var time:Int
var values:[String]
var jsonRepresentation : String {
return """
{
"name":"\(name)",
"time":\(time),
"values":\(values)
}
"""
}
}
Here is the json format that the external api recieves.
{
"op" : "delete",
"rec": {
"name" : "some string",
"time":200,
"values": [
"127.0.0.1"
]
}
}
Here is my function the creates the HTTP request
private func createPatchRequest(op: String, url: URL, rec: Rec) throws -> URLRequest {
let dictionary: [String: String] = [
"op":op,
"rec":rec.jsonRepresentation
]
let jsonData = try JSONEncoder().encode(dictionary)
var request = URLRequest(url: url)
request.httpMethod = "PATCH"
request.httpBody = jsonData
request.addValue("application/json", forHTTPHeaderField:"Content-Type")
return request
}
I always get a 400 and i believe that swift isn't' encoding my json properly. I tried the request on postman and it worked fine!
Here is how it looked on postman
{
"op" : "delete",
"rec": {
"name" : "some string",
"time":600,
"values": [
"127.0.0.1"
]
}
}
Any ideas? Thanks!
Upvotes: 2
Views: 9030
Reputation: 10095
The problem is that the API expects rec
to be a JSON object, but you're sending Rec as a string representation of a JSON Object. i.e. This is the JSON that you're sending:
{
"rec": "{\n\"name\":\"some string\",\n\"time\":1,\n\"values\":[\"127.0.0.1\"]\n}",
"op": "delete"
}
The ideal approach would be to create a Codable
PatchRequest
with a nested Rec
struct and encode that. You can try the following snippet on Playground
struct Rec : Codable {
var name:String
var time:Int
var values:[String]
}
struct PatchRequest : Codable{
var op: String
var rec: Rec
}
let rec = Rec(name: "some string",time: 600,values: ["127.0.0.1"])
let request = PatchRequest(op: "delete",rec: rec)
let jsonData = try JSONEncoder().encode(request)
let jsonString = String(data: jsonData, encoding: .utf8)
This has the added benefit of reducing the number of parameters required by your API method and making the code cleaner overall:
private func createPatchRequest(url: URL, patchRequest: PatchReuest) throws -> URLRequest {
let jsonData = try JSONEncoder().encode(patchRequest)
var request = URLRequest(url: url)
request.httpMethod = "PATCH"
request.httpBody = jsonData
request.addValue("application/json", forHTTPHeaderField:"Content-Type")
return request
}
Lastly, I would recommend using let
in your structs instead of var
unless it's absolutely necessary.
Upvotes: 7
Reputation: 8147
Your jsonRepresentation is a string but should be a dictionary. Update your struct this way:
struct Rec : Codable {
var name:String
var time:Int
var values:[String]
var jsonRepresentation: [String: Any] {
return [
"name": name,
"time": time,
"values": values
]
}
}
Hope it helps! Please let me know if it worked.
Upvotes: 1