0

I Have the following JSON response from API,

{
    "status_code": 1000,
    "data": [
        {
            "id": 3,
            "invoice_id": 100000,
            "user_id": 1000,
            "contact_number": "NA",
            "province": 0,
            "location": "100000",
            "total": 0,
            "confirm_code": 1234,
            "status": 0,
            "created_at": "2020-03-18 22:07:25",
            "updated_at": "2020-03-18 22:07:25"
        },
        {
            "id": 4,
            "invoice_id": 100000,
            "user_id": 1000,
            "contact_number": "NA",
            "province": 0,
            "location": "100000",
            "total": 0,
            "confirm_code": 1234,
            "status": 0,
            "created_at": "2020-03-18 22:10:40",
            "updated_at": "2020-03-18 22:10:40"
        },
        {
            "id": 5,
            "invoice_id": 100000,
            "user_id": 1000,
            "contact_number": "NA",
            "province": 0,
            "location": "100000",
            "total": 0,
            "confirm_code": 1234,
            "status": 0,
            "created_at": "2020-03-18 22:12:29",
            "updated_at": "2020-03-18 22:12:29"
        }
    ],
    "message": null
}

and my struct is,

struct Invoice: Codable {
    let statusCode: Int
    let data: [Datum]
    let message: String?

    enum CodingKeys: String, CodingKey {
        case statusCode
        case data, message
    }
}

struct Datum: Codable {
    let id, invoiceID, userID: Int
    let contactNumber: String
    let province: Int
    let location: String
    let total, confirmCode, status: Int
    let createdAt, updatedAt: String

    enum CodingKeys: String, CodingKey {
        case id
        case invoiceID
        case userID
        case contactNumber
        case province, location, total
        case confirmCode
        case status
        case createdAt
        case updatedAt
    }
}

and In View Controller,

override func viewDidLoad() {
        super.viewDidLoad()

        let url = URL(string: "http://xxxxx/api/invoices/\(1000)")!
        var request = URLRequest(url: url)
        request.httpMethod = "get"
        let task = session.dataTask(with: request) { (data, response, error) in
            guard let data = data else { return }
            do {
                let jsonData = try JSONDecoder().decode([Invoice].self, from: data)
                print(jsonData)
            }
            catch let jsonerr {
                print("error serrializing error",jsonerr)
            }

        }
        task.resume()
    }

But Im keeping below error message,

error serrializing error typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))

Please what Im missing here ! Any help will be much appreciated

4
  • 3
    Can you explain why you wrote [Invoice].self instead of Invoice.self? Commented Mar 26, 2020 at 16:00
  • As Sweeper suggested, in the json you have only an object not an array of object. Commented Mar 26, 2020 at 16:02
  • 1
    And you will get a few more errors unless you specify the convertFromSnakeCase strategy and delete all CodingKeys. Commented Mar 26, 2020 at 16:04
  • Thank you all guys, it was my mistake with the brackets Commented Mar 26, 2020 at 16:48

1 Answer 1

1

The Codable struct will be like

struct Invoice: Codable {
    let statusCode: Int
    let data: [Datum]
    let message: String?

    enum CodingKeys: String, CodingKey {
        case statusCode = "status_code"
        case data, message
    }
}

struct Datum: Codable {
    let id, invoiceID, userID: Int
    let contactNumber: String
    let province: Int
    let location: String
    let total, confirmCode, status: Int
    let createdAt, updatedAt: String

    enum CodingKeys: String, CodingKey {
        case id = "id"
        case invoiceID = "invoice_id"
        case userID = "user_id"
        case contactNumber = "contact_number"
        case province, location, total
        case confirmCode = "confirm_code"
        case status
        case createdAt = "created_at"
        case updatedAt = "updated_at"
    }
}

And also use

let jsonData = try JSONDecoder().decode(Invoice.self, from: data)

instead of

 let jsonData = try JSONDecoder().decode([Invoice].self, from: data)
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Man, I forgot the brackets (:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.