LondonGuy
LondonGuy

Reputation: 11098

How do I read the property values of a JSON error object using Combine in Swift?

All of my API endpoints return a response which looks something like this in Postman:

{
    "statusCode": 401,
    "error": "Unauthorized",
    "message": "Missing authentication"
}

What I would like to do is make the request, and have access to these properties in Swift. There will be some cases where I use the error message property's value in the front of the app. This will be determined by the statusCode returned.

What I have right now is this:

    private var cancellable: AnyCancellable?
    let url = URL(string: "http://abc336699.com/create")
    self.cancellable = URLSession.shared.dataTaskPublisher(for: url!)
      .map { $0.data }

Prior to this, I tried tryMap, but the type of error it returned didn't give me the flexibility I wanted. I then moved on and tried Almofire, but it seemed like an over kill for what I want to do.

I wanted to check what is being returned in the response I get, but I get the following error:

Cannot assign value of type 'Publishers.Map<URLSession.DataTaskPublisher, Data>' to type 'AnyCancellable'

I want simple access to my response errors so I can integrate the API throughout the app using combine.

Upvotes: 0

Views: 584

Answers (1)

user832
user832

Reputation: 846

I am not sure from where you will be getting your data as in JSON response there is no Key for data. Before writing below code my understanding was that you want to check error and statusCode from the mentioned JSON response and then move forward with your business logic. The below code is to give you a vague idea of how we can do that.

    enum CustomError: Error {

    case custom(_ error: String)
    case unknownStatusCode
    case errorOccurred
}

let url = URL(string: "http://abc336699.com/create")

    func load() -> AnyPublisher<Data,CustomError> {
    URLSession.shared.dataTaskPublisher(for: url!)
        .map(\.data)
        .tryMap { (data) -> Data in
            let genericModel = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: AnyObject]

            if let statusCode = genericModel?["statusCode"] as? String {
                switch statusCode {
                case "200":
                    guard let data = genericModel?["message"] as? Data else {
                        throw CustomError.custom("Parsing error")
                    }
                    return data
                default:
                    if let error = genericModel?["error"] as? String {
                        throw CustomError.custom(error)
                    } else {
                        throw CustomError.unknownError
                    }
                }
            }
            throw CustomError.errorOccurred
    }
    .decode(type: YourCustomDecodableModel.self, decoder: JSONDecoder())
    .mapError({ $0 as? CustomError ?? CustomError.errorOccurred })
    .eraseToAnyPublisher()
}

Upvotes: 1

Related Questions