skip to Main Content

Trying out the request on Postman, the "data" of the response is an empty dictionary.

postman response

However, when I try that in swift using Alamofire, "data" gets misinterpreted as an empty array. What could I be doing wrong?
alamofire response

Raw response using debugPrint(response) prints the following:

[Response]:
    [Status Code]: 200
    [Headers]:
        Access-Control-Allow-Origin: *
        Alt-Svc: h3=":443"; ma=2592000, h3-29=":443"; ma=2592000, h3-Q050=":443"; ma=2592000, h3-Q046=":443"; ma=2592000, h3-Q043=":443"; ma=2592000, quic=":443"; ma=2592000; v="43,46"
        Cache-Control: no-cache, private
        Content-Encoding: br
        Content-Length: 71
        Content-Type: application/json
        Date: Tue, 31 Jan 2023 16:32:18 GMT
        Vary: Accept-Encoding
        x-powered-by: PHP/8.0.24
        x-ratelimit-limit: 60
        x-ratelimit-remaining: 59
    [Body]:
        {"status":false,"message":"Kullanu0131cu0131 bilgileri hatalu0131.","data":[]}

Tried changing the encoding and headers of the request, none was helpful.

2

Answers


  1. This isn’t an Alamofire issue, it’s an error from JSONDecoder. You can check your actual response by printing the raw response in Alamofire (which you don’t post any code for).

    .response<...> { response in 
      debugPrint(response)
    }
    

    That will print a String version of the response body (unless it’s very large) which you can use to see what you’re actually receiving.

    You can also check your actual response using a proxy like Proxyman or a traffic inspector like Wireshark and see what you’re actually getting. It seems likely you’re actually receiving an array.

    Login or Signup to reply.
  2. I’ve come across this odd way of representing null from a server (openweathermap), where instead of null, it uses {}.
    To work with this, I used a custom decoder, something like:

    // for the case where we have:  "data": { } instead of, "data": null
    
    public init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        if let theData = try? values.decode([String].self, forKey: .data) {
            self.data = theData
        } else {
            self.data = nil
        }
        // ....other keys
    }
    

    with declaration, let data: [String]? or whatever the array holds.

    Note this is a JSONDecoder behaviour, not Alamofire, I was using URLSession.shared... with this. When the JSONDecoder tries to decode this {}, it crashes, because it is not an a null and it not an array either. Postman is probably more forgiving than Swift JSONDecoder. Alamofire tries to decode data as an array, because you probably declared it as an array in your struct/class to decode.

    EDIT-1:

    here is the SwiftUI code I used to test my answer (same approach for UIKit and Alamofire):

    struct RequestResponse: Decodable {
        var status: Bool
        var message: String?
        var data: [String]?
        
        enum CodingKeys: String, CodingKey {
            case status, message, data
        }
        
        // for the case where we have: "data": { } instead of, "data": null
        public init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            self.status = try values.decode(Bool.self, forKey: .status)
            self.message = try values.decode(String?.self, forKey: .message)
            if let theData = try? values.decode([String].self, forKey: .data) {
                self.data = theData
            } else {
                self.data = nil
            }
        }
    }
    
    struct ContentView: View {
        @State var response: RequestResponse?
        
        var body: some View {
            VStack {
                if let results = response {
                    Text(results.status ? "true" : "false")
                    Text(results.message ?? "no message")
                    ForEach(results.data ?? [], id: .self) { item in
                        Text("(item)")
                    }
                }
            }
            .onAppear {
                let json = """
    {
       "status": false,
       "message": "some message here",
       "data": {}
    }
    """
                // simulated API data from the server
                let data = json.data(using: .utf8)!
                do {
                    let decoded = try JSONDecoder().decode(RequestResponse.self, from: data)
                    print("n---> decoded: (decoded) n")
                    response = decoded
                } catch {
                    print("n---> error: n (error)n")
                }
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search