Search code examples
swifturlsessioncombine

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()

Solution

  • If I correctly understood your goal, you need something like

    }else{
        return Fail(error: ServiceError.badServiceReply)
                  .eraseToAnyPublisher()
    }
    

    Simple example:

    URLSession.shared
        .dataTaskPublisher(for: URL(string: "https://www.google.com")!)
        .receive(on: DispatchQueue.main)
        .flatMap { _ in
            Fail(error: URLError(URLError.unsupportedURL)).eraseToAnyPublisher()
        } //for the sake of the demo
        .replaceError(with: "An error occurred") //this sets Failure to Never
        .assign(to: \.stringValue, on: self)
        .store(in: &cancellableBag)
    

    would always assign string "An error occurred" due to remap to Fail publisher