Andy Nguyen
Andy Nguyen

Reputation: 461

Attempt at utilizing decodable

I am trying to create decodable structs for the JSON that I am receiving, but I keep getting:

keyNotFound(CodingKeys(stringValue: "inquiry_quantity", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "orders", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys...

This is the JSON that I am running through my decoder:

{
    "orders_important": 2,
    "orders_inquiry": 2,
    "orders": [

    {
        "information": {
            "total_price": 12.0,
            "order_stage": "CONFIRMED",
            "total_cases": 333,
            "scanned": false,
            "inquiry": false,
            "foodhub": "[email protected]",
            "identifier": "GPO00024",
            "delivery_date": "2019-11-04"
        },
        "details": {
            "pack_size": "40#",
            "cases": 333,
            "plu_code": 12434,
            "crop_plan": 1633,
            "commodity": "Conventional Bananas, , 40#"
        }
    },
    {
        "information": {
            "inquiree": "FARMER",
            "total_price": 23.5,
            "order_stage": "INQUIRY",
            "inquiry_quantity": 0,
            "total_cases": 56,
            "scanned": false,
            "inquiry": true,
            "foodhub": "[email protected]",
            "inquiry_type": "PRICE",
            "identifier": "GPO00027",
            "inquiry_price": 26.5,
            "delivery_date": "2019-11-05",
            "inquiry_details": "You have requested $26.5 per case, instead of $23.5."
        },
        "details": {
            "pack_size": "40#",
            "cases": 12,
            "plu_code": 12434,
            "crop_plan": 1589,
            "commodity": "Conventional Bananas, , 40#"
        }
    },
],
"orders_count": 4
}

My decodable structs: (EDIT: Removed Init)

struct OrderBundle: Decodable{
    let orders_important : Int
    let orders_inquiry:Int
    let orders_count: Int
    let orders: [Order]
}

struct Order: Decodable {
    let inquiry_quantity : Int
    let inquiry_price : Int
    let inquiry_info : String
    let price : Int
    let cropPlan : Int
    let identifier: String
    let deliveryDate : String
    let quantity : Int
    let unit : String
    let status : String
    let destination : String
    let commodity: String

}

And lastly calling my decoder:

let orderData = try
                    JSONDecoder().decode(OrderBundle.self, from: data!)
                print(orderData)

I have tried it with and without the Init in my Orders and both ways I am still getting the same error.

Upvotes: 0

Views: 68

Answers (1)

vadian
vadian

Reputation: 285069

The main issue is that any dictionary must be decoded to an extra struct if init(from decoder is not provided. So basically the structure of the model must be

struct OrderBundle: Decodable {
    struct Information : Decodable {
    struct Details : Decodable {

The complete structs are as follows, many struct members must be declared as optional and inquiryPrice is Double, not Int. convertFromSnakeCase converts the snaked_cased keys to camelCased struct members.

struct OrderBundle : Decodable{
    let ordersImportant : Int
    let ordersInquiry : Int
    let ordersCount : Int
    let orders : [Order]
}

struct Order : Decodable {

    let information : Information
    let details : Details

    struct Information : Decodable {
        let inquiryQuantity : Int?
        let inquiryPrice : Double?
        let inquiryInfo : String?
        let price : Int?
        let cropPlan : Int?
        let identifier : String
        let deliveryDate : String
        let quantity : Int?
        let unit : String?
        let status : String?
        let destination : String?
        let commodity: String?
    }

    struct Details : Decodable {
        let packSize : String
        let cases : Int
        let pluCode : Int
        let cropPlan : Int
        let commodity : String
    }
}

And the code to decode it

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let orderData = try decoder.decode(OrderBundle.self, from: data!)
print(orderData)

Upvotes: 3

Related Questions