5 Replies
      Latest reply on Dec 4, 2019 4:28 AM by OOPer
      GSpound Level 1 Level 1 (0 points)

        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?

        EXAMPLE:



        How would you recommend initializing an object from decoder that has say two different variations depending on where you are deserializing it from.  For Example

        Lets say I get the first book from http://library.com/bookLocations/{id}
        And the second book from http://library.com/bookInfo/{id}

        Book: { 
          Author: "James" 
          Title: "JamesBook" 
          LibraryId: "387fh384fh3i09" 
          SectionNumber: "870D" 
        } 
        
        

         

        Book: { 
          Author: "James" 
          Title: "JamesBook" 
          Length: "870" 
          Reviews: "9/10" 
        } 
        
        

         

        What is the best way to handle both cases inside

         

        1. init(from decoder: Decoder) 


        if I want to use the same model/object for both

         

         

        struct Book: Codable { 
          var author: String 
          var title: String 
          var libraryId: String? 
          var sectionNumber: String? 
          var length: String? 
          var reviews: String? 
        } 
        
        





        • Re: Extend JSONDecoder to allow for models to be serialized differently based on endpoint
          OOPer Level 8 Level 8 (5,435 points)

          `Decoder` is a protocol where all `Decodable` things rely on.

          You should better not implement `init(from decoder: Decoder)` using some extended feature of a specific `Decoder`.

           

          Please show more concrete examples, JSON texts of the endpoints and your model.

            • Re: Extend JSONDecoder to allow for models to be serialized differently based on endpoint
              GSpound Level 1 Level 1 (0 points)

              How then would you recommend initializing an object from decoder that has say two different variations depending on where you are deserializing it from.  For Example

              Lets say I get the first book from http://library.com/bookLocations/{id}
              And the second book from http://library.com/bookInfo/{id}


              Book: {
                Author: "James"
                Title: "JamesBook"
                LibraryId: "387fh384fh3i09"
                SectionNumber: "870D"
              }
              Book: {
                Author: "James"
                Title: "JamesBook"
                Length: "870"
                Reviews: "9/10"
              }


              What is the best way to handle both cases inside

              init(from decoder: Decoder)

              if I want to use the same model/object for both

              struct Book: Codable {
                var author: String
                var title: String
                var libraryId: String?
                var sectionNumber: String?
                var length: String?
                var reviews: String?
              }
                • Re: Extend JSONDecoder to allow for models to be serialized differently based on endpoint
                  OOPer Level 8 Level 8 (5,435 points)

                  In this simple case as in your example, you have no need to do anything special.

                  (Please show valid JSON texts, with easily testable code and data, more readers would test them and you would get more responses.)

                   

                  struct Book: Codable {
                      var author: String
                      var title: String
                      var libraryId: String?
                      var sectionNumber: String?
                      var length: String?
                      var reviews: String?
                      
                      enum CodingKeys: String, CodingKey {
                          case author = "Author"
                          case title = "Title"
                          case libraryId = "LibraryId"
                          case sectionNumber = "SectionNumber"
                          case length = "Length"
                          case reviews = "Reviews"
                      }
                  }
                  struct Result: Codable {
                      var book: Book
                      
                      enum CodingKeys: String, CodingKey {
                          case book = "Book"
                      }
                  }
                  
                  let endpoint1Text = """
                  {
                      "Book": {
                        "Author": "James",
                        "Title": "JamesBook",
                        "LibraryId": "387fh384fh3i09",
                        "SectionNumber": "870D"
                      }
                  }
                  """
                  
                  let endpoint2Text = """
                  {
                      "Book": {
                        "Author": "James",
                        "Title": "JamesBook",
                        "Length": "870",
                        "Reviews": "9/10"
                      }
                  }
                  """
                  
                  do {
                      let result1 = try JSONDecoder().decode(Result.self, from: endpoint1Text.data(using: .utf8)!)
                      print(result1)
                      let result2 = try JSONDecoder().decode(Result.self, from: endpoint2Text.data(using: .utf8)!)
                      print(result2)
                  } catch {
                      print(error)
                  }
                  
                  

                  Tested in Playgrounds, I get this.

                  Result(book: __lldb_expr_5.Book(author: "James", title: "JamesBook", libraryId: Optional("387fh384fh3i09"), sectionNumber: Optional("870D"), length: nil, reviews: nil))

                  Result(book: __lldb_expr_5.Book(author: "James", title: "JamesBook", libraryId: nil, sectionNumber: nil, length: Optional("870"), reviews: Optional("9/10")))

                   

                  Your actual model may be more complex and there may be some difficulties, but I cannot say any more without seeing it.