iosjsonswiftalamofireobject-object-mapping

Mapping a variety of JSON responses with the same top - level structure in Swift


I have a variety of JSON responses that I'm getting back from a server via Alamofire; two are included below:

1)

{
  "json" : {
    "harkUpdate" : {
      "more" : [
        {
          "unread-count" : {
            "last" : 1613507864973,
            "index" : {
              "graph" : {
                "graph" : "\/ship\/~dopzod\/urbit-help",
                "index" : "\/"
              }
            }
          }
        },
        {
          "seen-index" : {
            "index" : {
              "graph" : {
                "index" : "\/",
                "graph" : "\/ship\/~dopzod\/urbit-help"
              }
            },
            "time" : 1613507864973
          }
        }
      ]
    }
  },
  "response" : "diff",
  "id" : 3
}
    {
      "json" : {
        "graph-update" : {
          "keys" : [
            {
              "name" : "book-club-4717",
              "ship" : "sicdev-pilnup"
            },
            {
              "name" : "dm--locrev-finlys",
              "ship" : "haddef-sigwen"
            },
            {
              "name" : "smol-bibliotheca",
              "ship" : "dasfeb"
            },
            {
              "name" : "interface",
              "ship" : "bitpyx-dildus"
            },
            {
              "name" : "jobs-gigs",
              "ship" : "nibset-napwyn"
            },
            {
              "name" : "tlon-general",
              "ship" : "bolbex-fogdys"
            }
          ]
        }
      },
      "id" : 1,
      "response" : "diff"
    }

As you can see, they both have an id, a response, and json fields - but the actual json response in them varies.

Normally what I would do is generate classes using something like quicktype.io, or use one of the many ObjectMapping frameworks out there. What I'm trying to get mentally un-blocked with is that all these json responses have a field called "json", which has a different structure. I'm trying to figure out who I can make unique classes for the responses given this structuring. Any help appreciated.


Solution

  • You can declare a basic object which's json property will be a generic type conforming to Codable.

    struct JSON<T : Codable>: Codable {
        let json: T
        let id: Int
        let response: String
    }
    

    After you define two structs which will represent the first and second json objects. For simplicity I will define only the objects that represent the second JSON:

    struct GraphUpdate: Codable {
        let graphUpdate: Keys
    
        enum CodingKeys: String, CodingKey {
            case graphUpdate = "graph-update"
        }
    }
    
    struct Keys: Codable {
        let keys: [Key]
    }
    
    struct Key: Codable {
        let name, ship: String
    }
    

    And when trying to decode, you have to specify what object you want to decode to:

    let item = try? JSONDecoder().decode(JSON<GraphUpdate>.self, from: data)