Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

handling HTTP status code with URLSession and Combine

I'm trying to handle the responses that arrive from a DataTaskPublisher reading its response status code.

When status code is greater than 299, I'd like to return a ServiceError type as Failure. In every examples that I've seen I've used .mapError and .catch... in this specific case, from a .flatMap, I really don't know how to handle the publisher response to return the Error instead of the TResponse...

    return URLSession.DataTaskPublisher(request: urlRequest, session: .shared)
        .mapError{error in return ServiceError.request}
        .flatMap{ data, response -> AnyPublisher<TResponse, ServiceError> in

            if let httpResponse = response as? HTTPURLResponse,
                (200...299).contains(httpResponse.statusCode){

                return Just(data)
                    .decode(type: TResponse.self, decoder: JSONDecoder())
                    .mapError{error in return ServiceError.decode}
                    .eraseToAnyPublisher()
            }else{
                //???? HOW TO HANDLE THE ERROR?
            }
        }
        .receive(on: RunLoop.main)
        .eraseToAnyPublisher()
like image 202
MatterGoal Avatar asked Oct 20 '25 04:10

MatterGoal


1 Answers

enum ServiceErrors: Error { 
    case internalError(_ statusCode: Int)
    case serverError(_ statusCode: Int)
}
    
return URLSession.shared.dataTaskPublisher(for: urlRequest)
            .tryMap { data, response in
                guard let httpResponse = response as? HTTPURLResponse,
                    200..<300 ~= httpResponse.statusCode else {
                        switch (response as! HTTPURLResponse).statusCode {
                        case (400...499):
                            throw ServiceErrors.internalError((response as! HTTPURLResponse).statusCode)
                        default:
                            throw ServiceErrors.serverError((response as! HTTPURLResponse).statusCode)
                        }
                }
                return data
            }
            .mapError { $0 as! ServiceErrors }
            .decode(type: T.self, decoder: JSONDecoder())
            .receive(on: RunLoop.main)
            .eraseToAnyPublisher()

NOTE: I relied on this link to make my error handler.

like image 117
gandhi Mena Avatar answered Oct 21 '25 18:10

gandhi Mena