-1

I am developing an iOS app in Swift with a coworker.

I have an API I am using to retrieve some chats from a server. Every chat has a field message_id. I expect this to be a string, but the API sometimes gives it to me as an integer. Here is a sample of the JSON:

[
    {
        "id": 17,
        "message_id": "434",
        "last_sender_id": "121",
        "subject": {
            "rendered": "Re: No Subject"
        },
        "excerpt": {
            "rendered": "very good"
        },
        "message": {
            "rendered": "<p>very good</p>\n"
        },
        "date": "2023-06-21T14:32:47",
    },
    {
        "id": 17,
        "message_id": 430,
        "last_sender_id": "121",
        "subject": {
            "rendered": "Re: No Subject"
        },
        "excerpt": {
            "rendered": "Hi"
        },
        "message": {
            "rendered": "<p>Hi</p>\n"
        },
        "date": "2022-11-18T15:20:13",
    },
    {
        "id": 17,
        "message_id": "428",
        "last_sender_id": "121",
        "subject": {
            "rendered": "No Subject"
        },
        "excerpt": {
            "rendered": "Test"
        },
        "message": {
            "rendered": "<p>Test</p>\n"
        },
        "date": "2022-11-18T15:19:10",
    },
]

The API provider has confirmed this as a bug to fix in the future, but I have to find a workaround for it now. I asked my coworker can we not just convert the type from int to string when using it? (I am not the Swift expert). They said:

"that's not how that works, since I am getting message_id from JSON and I have to tell the converter before all objects are unpacked what to expect".

Is what they said correct? How do I workaround this bug?

Called the API. It sometimes gives the message_id as string, sometimes integers. This is a bug I need to work around for now until the provider fixes it. I have updated OP with what my co-worker says.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
swdr
  • 1
  • Ideally it should have a single data type, but if you are getting dynamic data type, then you can use `Any` like: var message_id = Any – Kudos Aug 01 '23 at 08:32
  • Speak to the back end devs and ask them to fix it – Fogmeister Aug 01 '23 at 08:38
  • @Kudos do you mind posting an example of how they can use `Any` please? They insisted that "I have to tell the converter before all objects are unpacked what to expect". – swdr Aug 01 '23 at 08:47
  • @Fogmeister I have - they said no promised timeline on the fix, but my development is held up, which is why I need to have a workaround for now! – swdr Aug 01 '23 at 08:48
  • @swdr no worries. I was only half joking. Also, don’t use `Any`. You should avoid using Any as much as possible. – Fogmeister Aug 01 '23 at 09:04
  • Use XML, in XML it will be always string. – Cy-4AH Aug 01 '23 at 11:31
  • JSON formats are usually represented as [String:Any] dictionaries in Swift so you can use Any data type and have the value be conditionally unwrapped and then use that value you get from that. let dict: [String:Any] = ["message_id": 434] if let intValue = dict["message_id"] as? Int { print("The value is an integer: \(intValue)") } else if let stringValue = dict["message_id"] as? String { print("The value is a string: \(stringValue)") } – devdchaudhary Aug 01 '23 at 18:08

1 Answers1

0

You can customize the init(from decoder: Decoder) method to differentiate specific types, (although this method is not recommended).

struct S: Codable {
    var id: String
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        if let strId = try? container.decode(String.self, forKey: .id) {
            self.id = strId
        } else if let intId = try? container.decode(Int.self, forKey: .id) {
            self.id = "\(intId)"
        } else {
            fatalError("")
        }
    }
}

let jsonWithStr = "{\"id\":\"11\"}".data(using: .utf8)!
let jsonWithInt = "{\"id\":11}".data(using: .utf8)!

print(try JSONDecoder().decode(S.self, from: jsonWithStr))
print(try JSONDecoder().decode(S.self, from: jsonWithInt))
ytshen
  • 1
  • 1
  • Thanks for this, could you please mention why it is not recommended? What are the implications of using this as a workaround until the API is fixed? – swdr Aug 01 '23 at 08:49
  • Fix the value to have a single type is the best solution. – ytshen Aug 01 '23 at 09:07