Search code examples
iosjsonswiftdecodingjsondecoder

Extend JSONDecoder to allow for models to be serialized differently based on endpoint


I have many models that, depending on the endpoint, or serialized differently. My first attempt had a init(from decoder: Decoder) riddled with nested try catch blocks. I thought a better solution would be to extend JSONDecoder so that when I initialize one, I can specify which endpoint i am pulling from. Then in my models init(from decoder: Decoder) I could have a switch like

switch
case endpoint1:
   x = decoder.decode(Int.self, .x)
case endpoint2:
   j = decoder.decode(String.self, .j)

The problem I ran into is that the class you have inside the init is a Decoder not a JSONDecoder. I can't figure out a place that, if I extend Decoder and allow myself to specify an endpoint, I could actually specify an endpoint, since JSONDecoder.decode() instantiates it's own Decoder behind the scenes. Thoughts?


Solution

  • I assumed after having previously used a CocoaPod for JSON Decoding and Encoding that I would actually need a way to handle different serializations of the same model, but thankfully Codable handles this almost on its own. Any members that will not appear in every serialization, just mark as optional with ? and if the Decoder can't find a key for it, it will skip it instead of fail. Similarly, the encoder will just encode members that are not nil. Example:

    class Book: Codable {
        var title: String
        var numPages: Int?
        var author: String?
        enum CodingKeys: String, CodingKey {
            case title
            case numPages = "number_of_pages"
            case author
        }
    }
    

    This model will be successfully decoded from JSON Data that has:

    1. Title
    2. Title and Number of Pages
    3. Title and Author
    4. Title, Number of Pages, and Author

    However, because title is not optional, if the JSON Data doesn't contain a title, it will fail.