Handle success response when there is no Data returned by the server with Combine

732 views Asked by At

I am trying to implement Networking with Combine Framework and I am able to fetch data from server using following code but I am facing an issue when there is no data returned from the server but the request was successful.

   return URLSession.shared.dataTaskPublisher(for: request)
      .tryMap { response in
         print(response)
        guard let httpURLResponse = response.response as? HTTPURLResponse, 200..<299 ~= httpURLResponse.statusCode  else {
           throw CustomError.serverError
         }
         if response.data.isEmpty && 200..<299 ~= httpURLResponse.statusCode {
            //HOW TO HANDLE IF if there is no Data from server but request has been processed successfully
         }
         return response.data
        }
        .decode(type: R.self, decoder: decoder)
        .mapError{CustomError.map(error: $0)}
        .receive(on: RunLoop.main)
        .eraseToAnyPublisher()
}

Can you please guide me on how to handle success response when there is no Data returned by the server.

Let me know if I have to elaborate on my question.

1

There are 1 answers

1
New Dev On BEST ANSWER

From your comments, since you need to either return the value of type R or "something" in case of successful but empty data response, then you could build a pipeline that returns an optional R?.

You'd need to use flatMap to handle this branch:

return URLSession.shared.dataTaskPublisher(for: request)
    .tryMap { response -> Data in
        guard let httpURLResponse = response.response as? HTTPURLResponse, 
           200..<299 ~= httpURLResponse.statusCode {
           throw CustomError.serverError
        }
        return response.data
    } 
    .flatMap { data -> AnyPublisher<R?, Error> in
       if data.isEmpty {
          return Just(nil).setFailureType(to: Error.self).eraseToAnyPublisher()
       }

       return Just(data).decode(type: R?.self, decoder: decoder)
          .eraseToAnyPublisher()
    }
    .mapError {
       $0 as? CustomError ?? CustomError.map(error: $0)
    }
    .receive(on: DispatchQueue.main)
    .eraseToAnyPublisher()

The pipeline above will return a R? value, and nil when data is empty.