Search code examples
jsonswiftrequestalamofiredecodable

Issue Parsing / Decoding JSON from API Endpoint Into Struct Object


I am writing a Swift 5.x app using Alamofire 5 to get a list of files from an API I wrote. The API returns the file list as a JSON Data object. I want to then get this data into a struct I created. I am not able to get this working. Here is an example JSON string that my server sends over when you hit the API endpoint:

[{
    "ID": "0d37ee7a-39bf-4eca-b3ec-b3fe840500b5",
    "Name": "File01.iso",
    "Size": 6148
}, {
    "ID": "656e0396-257d-4604-a85c-bdd0593290cd",
    "Name": "File02.iso",
    "Size": 224917843
}, {
    "ID": "275fdf66-3584-4899-8fac-ee387afc2044",
    "Name": "File04.iso",
    "Size": 5549504
}, {
    "ID": "1c73f857-56b5-475b-afe4-955c9d2d87fe",
    "Name": "File05.iso",
    "Size": 15476866871
}, {
    "ID": "bfebbca2-49de-43d7-b5d0-3461b4793b62",
    "Name": "File06.iso",
    "Size": 37254264
}]

I created the following Data Model in swift to hold this:

struct Files: Decodable {
    let root: [File]
}

struct File: Decodable, Identifiable {
    var id: UUID
    var name: String
    var size: Int
}

enum CodingKeys: String, CodingKey {
    case id = "ID"
    case name = "Name"
    case size = "Size"
}

Then I used Alamofire 5.x to call the API endpoint and attempt to decode the JSON and place it into the object in question:

func getPackageFilesJSON() {
    AF.request("http://localhost:8080/api/v1/list/pkgs").responseDecodable(of: Files.self) { response in
        guard let serverFiles = response.value else {
            print("Error Decoding JSON")
            return
        }
        let self.serverFilesList = serverFiles
    }
}

This fails. If I debugPrint the response I get this for the result:

[Result]: failure(Alamofire.AFError.responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.decodingFailed(error: Swift.DecodingError.typeMismatch(Swift.Dictionary<Swift.String, Any>, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Dictionary<String, Any> but found an array instead.", underlyingError: nil)))))

I have never been great at creating these data models and decoding JSON into them. I am sure I am missing something silly. I am hopeful that someone more knowledgable than me, or a second set of eyes can help me get this working.

Thanks, Ed


Solution

  • There is no key root in the JSON. The root object is an array

    Delete

    struct Files: Decodable {
       let root: [File]
    }  
    

    and decode

    AF.request("http://localhost:8080/api/v1/list/pkgs").responseDecodable(of: [File].self) { response in ...
    

    and move the CodingKeys enum into the File struct

    struct File: Decodable, Identifiable {
        var id: UUID
        var name: String
        var size: Int
        
        enum CodingKeys: String, CodingKey {
            case id = "ID"
            case name = "Name"
            case size = "Size"
        }
    }