Skip to content

Instantly share code, notes, and snippets.

@paulomendes
Created June 15, 2021 12:29
Show Gist options
  • Save paulomendes/eb12af3e8104545911a8fea8a38fd409 to your computer and use it in GitHub Desktop.
Save paulomendes/eb12af3e8104545911a8fea8a38fd409 to your computer and use it in GitHub Desktop.
Simple combine network client with retry mechanism
enum NetworkRequestProviderError: Error {
case badRequest
case unauthorized
case forbidden
case notFound
case error4xx(Int)
case error5xx(Int)
case serverError
case unknownError
case urlSessionFailed(URLError)
case decodingError
case malformedURL
}
typealias JSON = JSONDecoder.Input
typealias DataTaskResult = Result<JSON, Error>
final class NetworkRequestProvider<Endpoint: EndpointDescription> {
func request<Model: Decodable>(endpoint: Endpoint) -> AnyPublisher<Model, NetworkRequestProviderError> {
guard let request = try? endpoint.request() else {
return Result.Publisher(NetworkRequestProviderError.malformedURL).eraseToAnyPublisher()
}
return URLSession.shared
.dataTaskPublisher(for: request)
.tryMap({ data, response -> DataTaskResult in
if let response = response as? HTTPURLResponse,
!(200...299).contains(response.statusCode) {
throw self.httpError(response.statusCode)
}
return .success(data)
})
.catch { error -> AnyPublisher<DataTaskResult, Error> in
switch error {
case NetworkRequestProviderError.unknownError:
return Fail(error: error)
.delay(for: 2, scheduler: DispatchQueue.main)
.eraseToAnyPublisher()
default:
return Just(.failure(error))
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
}
.retry(2)
.tryMap { try $0.get() }
.decode(type: Model.self, decoder: JSONDecoder())
.mapError({ self.handleError($0) })
.eraseToAnyPublisher()
}
private func handleError(_ error: Error) -> NetworkRequestProviderError {
switch error {
case is Swift.DecodingError:
return .decodingError
case let urlError as URLError:
return .urlSessionFailed(urlError)
case let error as NetworkRequestProviderError:
return error
default:
return .unknownError
}
}
private func httpError(_ statusCode: Int) -> NetworkRequestProviderError {
switch statusCode {
case 400: return .badRequest
case 401: return .unauthorized
case 403: return .forbidden
case 404: return .notFound
case 402, 405...499: return .error4xx(statusCode)
case 500: return .serverError
case 501...599: return .error5xx(statusCode)
default: return .unknownError
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment