Last active
May 22, 2022 19:03
-
-
Save ankittlp/bf42cfc9b11cb3770f895b126e3f30ed to your computer and use it in GitHub Desktop.
NetworkLayerCombineTypeRequestExecutor.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class WebApiClient: RequestExecutor { | |
private var configuration: URLSessionConfiguration | |
private var session: URLSession | |
init(sessionConfiguration: URLSessionConfiguration = URLSessionConfiguration.default) { | |
configuration = URLSession.shared.configuration | |
session = URLSession(configuration: configuration) | |
} | |
func executeRequest<R>(request: R) -> AnyPublisher<R.Response, Error> where R : RequestConvertable { | |
// 1 | |
// Using Fail publisher this will help us to remove the `try! request.asURLRequest()` and make a early exit with guard in place. | |
guard let requestt = try? request.asURLRequest() else { | |
return Fail(error: APIError.badRequest()).eraseToAnyPublisher() | |
} | |
// 2 | |
// Earlier i was using Current value subject that act as an publisher which emit void value and can fail with error. | |
/* | |
CurrentValueSubject<Void,Error>(()).tryMap { () in | |
throw APIError.badRequest() | |
} | |
*/ | |
// /*try! request.asURLRequest()*/ | |
// 3 | |
return session.dataTaskPublisher(for: requestt) | |
// 4 | |
.tryMap({ [self] (data: Data, response: URLResponse) -> Data in | |
if let httpResponse = response as? HTTPURLResponse { | |
if request.reponseValidRange.contains(httpResponse.statusCode) { | |
return data | |
}else { | |
throw parseError(data: data, response: response, errorParser: request.errorParser) | |
} | |
} else { | |
throw APIError.invalidResponse() | |
} | |
}) | |
// 5 | |
.tryMap { returnData in | |
if let parser = request.parser { | |
do { | |
return try parser.parse(data: returnData) | |
} catch { | |
throw APIError.parseError(error) | |
} | |
} else { | |
do { | |
return try JSONDecoder().decode(R.Response.self, from: returnData) | |
} catch { | |
throw APIError.parseError(error) | |
} | |
} | |
} | |
// 6 | |
.mapError({ error in | |
if let error = error as? APIError { | |
return error | |
} else { | |
return APIError.unknown(error) | |
} | |
}) | |
// 7 | |
.receive(on: RunLoop.main) | |
// 8 | |
.eraseToAnyPublisher() | |
} | |
private | |
func parseError(data: Data, response: URLResponse, errorParser: ErrorParserType?) -> Error { | |
var errorToReturn: Error? | |
if let httpUrlResponse = response as? HTTPURLResponse { | |
if let errorParser = errorParser | |
{ | |
if let json = try? JSONSerialization.jsonObject(with: data, options: []) as? JSONDictionary { | |
if let parsedError = errorParser.parse(data: json) { | |
errorToReturn = parsedError | |
} | |
} | |
} | |
switch httpUrlResponse.statusCode { | |
case 400: | |
errorToReturn = APIError.badRequest(errorToReturn) | |
case 401: | |
errorToReturn = APIError.unAuthorised(errorToReturn) | |
case 404: | |
errorToReturn = APIError.notFound(errorToReturn) | |
case 400...499: | |
break | |
case 500...599: | |
errorToReturn = APIError.serverError() | |
default: | |
errorToReturn = APIError.unknown() | |
} | |
} | |
return errorToReturn ?? APIError.invalidResponse() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment