6

I am developing an application with Swift 4. Where I make a call to the APIRest with Alamofire and I want to map the JSON response with Objectmapper. Well, the JSON that calls me back is the following:

enter image description here

The code to the APIRest is:

    func retrievePostListData() {
        Alamofire
            .request("http://www.speedrun.com/api/v1/games", method: .get)
            .validate()
            .responseArray(completionHandler: { (response: 
            DataResponse<[PostModelSpeedRunModel]>) in
                switch response.result {
                case .success(let posts):

                 self.remoteRequestHandler?.onPostsRetrievedData(posts)
                    case .failure( _):
                        self.remoteRequestHandler?.onError()
                }
            })
    }

The problem is that I do not know how to access each of the values (func mapping). Because there are some nested values. In addition to that some of the annunciations are objects and others are array. My erroneous code is the following:

import Foundation
import ObjectMapper

struct PostModelSpeedRunModel {
    var id              = ""
    var international   = ""
    var abbreviation    = ""
    var links           = [Links]??? // I need to get "rel" and "uri" of "runs"
    var uri             = ""
}

extension PostModelSpeedRunModel: Mappable {

    init?(map: Map) {
    }

    mutating func mapping(map: Map) {
        id              <- map["data.id"]
        international   <- map["data.international"]
        abbreviation    <- map["data.abbreviation"]
        link              <- map["data.Links"]
        uri             <- map["data.logo"]
    }

}

Can you help me do / understand doing the function mapping? Thanks

1 Answers1

0

I'm assuming you are getting no values at all, because I tried your code and got nothing. If you only need the contents of the data array from the json and, as you have it now, ObjectMapper is expecting a json with just an array of PostModelSpeedRunModels. Therefore, you need to add a keyPath to tell AlamofireObjectMapper it's starting point:

    Alamofire.request("http://www.speedrun.com/api/v1/games", method: .get)
        .responseArray(keyPath: "data") { (response: DataResponse<[PostModelSpeedRunModel]>) in
            ...
    }

If you also need the info from the pagination node, then you'll need to create a new object that has a data and pagination properties, and change responseArray(keyPath: ...) to simply responseObject using the new root object in DataResponse.

Then I believe you only want runs's uri, so I recommend just having a String in your model for storing it, instead of an array of Links. Assuming that the array of links is unsorted and may change order in the future (if not you can access directly like map["links.1.uri"] and you are done), all links need to be parsed and then filtered. It can be done as follows:

struct PostModelSpeedRunModel {
    var id              = ""
    var international   = ""
    var abbreviation    = ""
    var runsLink        = ""
    var uri             = ""
}

extension PostModelSpeedRunModel: Mappable {

    init?(map: Map) {
    }

    mutating func mapping(map: Map) {
        id              <- map["id"]
        international   <- map["international"]
        abbreviation    <- map["abbreviation"]
        uri             <- map["logo"]

        var links: [Link]?
        links <- map["links"]

        if let uri = links?.first(where: {$0.rel == "runs"})?.uri {
            runsLink = uri
        }
    }
}

struct Link {
    var rel = ""
    var uri = ""
}

extension Link: Mappable {
    init?(map: Map) {
    }

    mutating func mapping(map: Map) {
        rel <- map["rel"]
        uri <- map["uri"]
    }
}