Home > OS >  Swift Data Model from JSON Response
Swift Data Model from JSON Response

Time:11-28

I am running into an issue building the correct data model for the following JSON response.

{
  "resources": [
    {
      "courseid": 4803,
      "color": "Blue",
      "teeboxtype": "Championship",
      "slope": 121,
      "rating": 71.4
    },
    {
      "courseid": 4803,
      "color": "White",
      "teeboxtype": "Men's",
      "slope": 120,
      "rating": 69.6
    },
    {
      "courseid": 4803,
      "color": "Red",
      "teeboxtype": "Women's",
      "slope": 118,
      "rating": 71.2
    }
  ]
}

Here is the current model. No matter what I do I can't seem to get the model populated. Here is also my URL session retrieving the data. I am new to Swift and SwiftUI so please be gentle. I am getting data back however I am missing something.

import Foundation

struct RatingsResources: Codable {
    let golfcourserating : [GolfCourseRating]?
}
    
    struct GolfCourseRating: Codable {
        let id: UUID = UUID()
        let courseID: Int?
        let teeColor: String?
        let teeboxtype: String?
        let teeslope: Double?
        let teerating: Double?
        
        enum CodingKeysRatings: String, CodingKey {
            case courseID = "courseid"
            case teeColor = "color"
            case teeboxtype
            case teeslope = "slope"
            case teerating = "rating"
        }
    }

    func getCoureRating(courseID: String?) {
       let semaphore = DispatchSemaphore (value: 0)
       
       print("GETTING COURSE TEE RATINGS..........")
       
       let urlString: String = "https://api.golfbert.com/v1/courses/\(courseID ?? "4800")/teeboxes"
       
       print ("API STRING: \(urlString) ")
       
       let url = URLComponents(string: urlString)!
       let request = URLRequest(url: url.url!).signed
       let task = URLSession.shared.dataTask(with: request) { data, response, error in
       let decoder = JSONDecoder()
            
            guard let data = data else {
                print(String(describing: error))
                semaphore.signal()
                return
            }
           
               if let response = try? JSONDecoder().decode([RatingsResources].self, from: data) {
                   DispatchQueue.main.async {
                       self.ratingresources = response
                   }
                   return
               }

           print("*******Data String***********")
           print(String(data: data, encoding: .utf8)!)
           print("***************************")
           
           let ratingsData: RatingsResources = try! decoder.decode(RatingsResources.self, from: data)
           
           print("Resources count \(ratingsData.golfcourserating?.count)")
           
             semaphore.signal()
           }

           task.resume()
           semaphore.wait()
           
   } //: END OF GET COURSE SCORECARD

CodePudding user response:

First of all, never use try? while decoding your JSON. This will hide all errors from you. Use try and an appropriate do/catch block. In the catch block at least print the error.

Looking at your model there seem to be three issues here.

  • You don´t have an array of RatingsResources in your array. It is just a single instance.

    let response = try JSONDecoder().decode(RatingsResources.self, from: data)
    
  • RatingsResources is not implemented correct.

    let golfcourserating : [GolfCourseRating]?
    

    should be:

    let resources: [GolfCourseRating]?
    
  • Your coding keys are implemented wrong instead of:

    enum CodingKeysRatings: String, CodingKey {
    

    it should read:

    enum CodingKeys: String, CodingKey {
    

CodePudding user response:

You should add enum CodingKey with resources at struct RatingsResources

And decode:

if let response = try? JSONDecoder().decode(RatingsResources.self, from: data) {
  // Your response handler
}
  • Related