Search code examples
jsonswiftjsondecoder

How do I decode from openFoodFacts JSON(Swift)


I'm fairly new to decoding from a JSON file.

My question is, how do I decode to find this: "product_name_en": "Coca Cola"(there's a lot more to that file, but not the node)

My struct is set up as:

struct ParseStructs : Decodable {

   var product_name_en : String

}

and my retrieve code is:

var testCall = "https://world.openfoodfacts.org/api/v0/product/5449000000996.json"



func request(urlString : String ){

    if let url = URL(string: urlString){

        let session = URLSession(configuration: .default)

        let task = session.dataTask(with :url) { (data , response , error) in

            if(error != nil){
                print(error!)
            }

                if let safeData = data{

                    print(safeData)
                    self.parseFunc(inputData: safeData)
                }

        }
        task.resume()
    }

}


func parseFunc(inputData : Data){

    let decoder = JSONDecoder()


    do{
    let decode = try decoder.decode(ParseStructs.self, from: inputData)
        print(decode)
    }catch{
        print(error)
    }

}

I just keep running into this lovely issue from the terminal line: 71733 bytes

keyNotFound(CodingKeys(stringValue: "product_name_en", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"product_name_en\", intValue: nil) (\"product_name_en\").", underlyingError: nil))

I've noticed that a lot of these questions gets hit with dislikes, but any help would be appreciated.


Solution

  • Your struct assumes the following JSON structure:

    {
        "product_name_en": "Coca Cola"
    }
    

    while in fact the data you are interested in is wrapped in another object:

    {
        "product": {
            "product_name_en": "Coca Cola"
        }
    }
    

    Typically, you'd solve this by defining another intermediate struct:

    struct Product: Decodable {
        var product_name_en: String
    }
    
    struct ProductWrapper: Decodable {
        var product: Product
    }
    

    and then decode this in your parseFunc function:

    let decoded = try decoder.decode(ProductWrapper.self, from: inputData)
    let product = decoded.product
    

    There are other ways to work around this, check out the "Dealing with Object Wrapping Keys" section of this awesome guide.