Incorrect JSON Format with JSONEncoder

Hi,

I have a struct that I'd like to encode with JSON and send in the body of an HTTP request:


struct AccountCreationData: Codable, Hashable {
    var name: String
    var email: String
    var phone: String
    var password: String
    
    private enum CodingKeys: String, CodingKey {
        case name
        case email
        case phone
        case password
    }
}

I encode it with this code and set the HTTP request body to the encoded data:

guard let encoded = try? JSONEncoder().encode(account) else {
        print("Failed to encode request")
        return
      }

request.httpBody = encoded

But in my backend, when I receive the data from the HTTP request, the JSON data is formatted as such:

 '{"phone":"0000000000",
    "password":"password",
    "email":"email",",
    "name":"name"}': ''}

Instead of:

{
    "phone": "0000000000",
    "password":"password"
    "email":"email"
    "name":"name"
}

So the JSON parser in my backend isn't properly parsing the data because of the format that the JSON is in. I was wondering if this is an issue with the way I'm encoding on the front end (Swift) or my backend. I have similar projects using the same code to encode the data so I'm unsure as to what the issue is. Any help would be greatly appreciated. Thank you.

Answered by Scott in 796744022
AccountCreationData(name: "name", email: "email", phone: "phone", password: "password")
110 bytes

Something is off. Testing here, if I encode your struct with those exact values, the result is 69 bytes, not 110 bytes. Can you print out a string representation of the encoded JSON?

And separately, do you need to set a Content-Type: application/json header so your server knows that the body format is JSON?

Could you show how you defined account (its content) ?

And print a log and report what you get:

guard let encoded = try? JSONEncoder().encode(account) else {
        print("Failed to encode request")
        return
      }

request.httpBody = encoded
print("encoded", encoded)

Hi,

Thank you for your response. Here is the whole function:

func createAccount(account: AccountCreationData, completion: @escaping (Response) -> Void) {
        guard let url = URL(string: "http://localhost:4300/account/create-account") else { return }
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
    
        print(account)
        
        guard let encoded = try? JSONEncoder().encode(account) else {
            print("Failed to encode request")
            return
        }
        
        print(encoded)
        
        request.httpBody = encoded
        
        URLSession.shared.dataTask(with: request) { (data, response, error) in
            guard let data = data else { return }
            
            do {
                let resData = try JSONDecoder().decode(Response.self, from: data)
                DispatchQueue.main.async {
                    completion(resData)
                }
            } catch let jsonError as NSError {
                print("JSON decode failed: \(jsonError)")
            }
        }.resume()
    }

Below are print statements of account and encoded:

AccountCreationData(name: "name", email: "email", phone: "phone", password: "password")
110 bytes

Can you show us what Response is? That's what you're decoding the JSON into.

Also, can you change this to something else? I don't like the re-use of the data variable, and it might be an issue later:

guard let data = data else { return }

// Maybe:
guard let jsonData = data else { return }

If not, it's good to clear it up anyway :)

Accepted Answer
AccountCreationData(name: "name", email: "email", phone: "phone", password: "password")
110 bytes

Something is off. Testing here, if I encode your struct with those exact values, the result is 69 bytes, not 110 bytes. Can you print out a string representation of the encoded JSON?

And separately, do you need to set a Content-Type: application/json header so your server knows that the body format is JSON?

print(encoded) returns 110 bytes.

When I test it with the following code,

let account = AccountCreationData(name: "name", email: "email", phone: "phone", password: "password")
if let encoded = try? JSONEncoder().encode(account) {
    print("encoded", encoded)
    print("content", String(data: encoded, encoding: .utf8)!) // To see the content of encoding
} else {
    print("Failed to encode request")
}

I get

encoded 69 bytes // (the string 'name: "name", email: "email", phone: "phone", password: "password"' is 66 bytes)
content {"email":"email","password":"password","name":"name","phone":"phone"}

Could you print the same log on your side ?

And please show how you call createAccount. You may have a problem there.

Also, why do you dispatch here:

                DispatchQueue.main.async {
                    completion(resData)
                }
            } catch let jsonError as NSError {

Hi,

Thank you for all the help. There was a discrepancy in the bytes because I removed a field from the data set. I was missing the Content-Type: application/json header which caused the issue.

Incorrect JSON Format with JSONEncoder
 
 
Q