1

I have a very simple model struct Student which only has two properties firstName and lastName:

struct Student {
    let firstName: String
    let lastName: String

    init(_ firstName: String, _ lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }

    // Convert to json data
    func toData() -> Data? {
        var json = [String: Any]()
        let mirror = Mirror(reflecting: self)
        for child in mirror.children {
            if let key = child.label?.trimmingCharacters(in: .whitespacesAndNewlines) {
                json[key] = child.value
            }
        }
        do {
            return try JSONSerialization.data(withJSONObject: json, options: [])
        } catch {
            print("\(error.localizedDescription)")
        }

        return nil
    }
}

As you see above, I created an toData() function which I use to convert model object to JSON data for my HTTP request body.

I create Student instance by:

let student = Student("John", "Smith")

I got Json Data by:

let jsonData = student.toData()

later I set to my URLRequest body by:

request.httpBody = jsonData!

However, backend team always see :

{\"firstName\":\"John\", \"lastName\":\"Smith\"}

But backend expect:

{"firstName":"John", "lastName":"Smith"}

I am sure it is not backend problem. Looks like something needs to improve in my toData() function. But I don't know what to do. Could someone help me?

Leem.fin
  • 40,781
  • 83
  • 202
  • 354
  • Possible duplicate of [how to prevent NSJSONSerialization from adding extra escapes in URL](https://stackoverflow.com/questions/19651009/how-to-prevent-nsjsonserialization-from-adding-extra-escapes-in-url) – Tamás Sengel Aug 17 '17 at 15:59
  • Why don't you generate the JSON dictionary manually, generating a JSON manually, then de-serializing and printing it seems to be giving the correct results. If your real class is way more complicated with a lot of fields, you could use a 3rd party library like ObjectMapper to solve this issue or wait for Swift4's Codable protocol. – Dávid Pásztor Aug 17 '17 at 16:43
  • The **JSON** `{\"firstName\":\"John\", \"lastName\":\"Smith\"}` that backend team sees is the valid `JSON` format. What's wrong with that? – nayem Aug 17 '17 at 17:10
  • @DávidPásztor, could you please make an example as answer? – Leem.fin Aug 17 '17 at 17:11
  • @Leem.fin sorry for the late answer, but I wanted to test it on a server as well, before posting. See my answer, finally I managed to test it and the results seem to be correct from the server logs. – Dávid Pásztor Aug 18 '17 at 09:02

2 Answers2

0

Try this :

if let jsonString:String = String(data: jsonData!, encoding: String.Encoding.utf8) {
    request.httpBody = jsonString.data(using: String.Encoding.utf8)
}
Vini App
  • 7,339
  • 2
  • 26
  • 43
0

You can get rid of the extra backslashes by converting your struct to a dictionary manually.

I have tested below method using a dummy rest server (rest-server-dummy from npm) and there are no extra backslashes around the "" characters.

struct Student {
    let firstName: String
    let lastName: String

    init(_ firstName: String, _ lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }

    // Convert to json data
    func toData() -> Data? {
        var json = [String: Any]()
        json["firstName"] = firstName
        json["lastname"] = lastName

        do {
            return try JSONSerialization.data(withJSONObject: json, options: [])
        } catch {
            print("\(error.localizedDescription)")
        }

        return nil
    }
}

I used this method to send the data to the dummy server running on localhost:

var request = URLRequest(url:URL(string: "http://localhost:8080/username")!)
request.httpMethod = "POST"
request.httpBody = student.toData()
URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in
    data
    response
    error
}).resume()

The contents of the output from the server log:

{
  "lastname": "Smith",
  "firstName": "John"
}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • Thanks, I will try it soon, and will get back to you. – Leem.fin Aug 18 '17 at 09:05
  • Hmm... interesting, I still get the same problem. – Leem.fin Aug 18 '17 at 09:08
  • Then the problem seems to be on the backend side, this code generates the expected results. Try running it yourself on the dummy server and see for yourself. Your backend might be doing the parsing incorrectly. – Dávid Pásztor Aug 18 '17 at 09:15
  • But backend works fine with another iOS app sending to the same endpoint. I checked the code of that app, it is in objective-c, and it uses the `AFStreamingMultipartFormData:appendPartWithFormData:name` for the payload... Now I get stuck what I should do to make it work with backend. – Leem.fin Aug 18 '17 at 09:53