Created
April 23, 2019 08:00
-
-
Save SergeyPetrachkov/9eb594e4f10e92d17fc94b7ca6036b02 to your computer and use it in GitHub Desktop.
Swagger helper with generic requestData
This file contains hidden or 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
| enum ServiceError: Error { | |
| case timeout | |
| case nilData | |
| } | |
| extension SwaggerClientAPI { | |
| private enum HeadersKeys: String { | |
| case authorization = "Authorization" | |
| } | |
| class func setBearer(_ token: String) { | |
| SwaggerClientAPI.customHeaders = [HeadersKeys.authorization.rawValue: "Bearer \(token)"] | |
| } | |
| class func clearBearer() { | |
| SwaggerClientAPI.customHeaders.removeValue(forKey: HeadersKeys.authorization.rawValue) | |
| } | |
| } | |
| /// A protocol which every api response with array of items must conform to | |
| protocol SequenceApiContainer { | |
| associatedtype T = Sequence | |
| /// array of items of any type | |
| var data: T? { get set } | |
| } | |
| /// A handler for swagger style responses | |
| class SwaggerApiResponseHandler { | |
| /// Request any data from service and return response model or throw an error | |
| /// - Parameters: | |
| /// - request: api request model provided by you swagger client (Models folder) | |
| /// - functor: method from your API class (APIs folder) | |
| /// - returns: unwrapped model of type declared by functor in `completion` | |
| /// - throws: Either Swagger handled error or `ServiceError.nilData` in any other case | |
| /// | |
| /// ``` | |
| /// let apiRequest = GetCompanyDetailsRequest(companyId: request.companyId, | |
| /// userLocation: request.geoPoint, | |
| /// locationId: request.cityId) | |
| /// let swaggerModelResponse = try SwaggerApiResponseHandler.requestData(request: apiRequest, | |
| /// functor: CompanyAPI.companyGetCompanyDetails) | |
| /// return Company(swaggerModel: swaggerModelResponse) | |
| /// ``` | |
| /// | |
| static func requestData<Request, Response>(request: Request, | |
| functor: @escaping ((_ request: Request, _ completion: @escaping (Response?, Error?) -> Void) -> Void)) throws -> Response { | |
| var result: Response? | |
| var outputError: Error? | |
| let dispatchGroup = DispatchGroup() | |
| dispatchGroup.enter() | |
| functor(request) { successfulResponse, failure in | |
| do { | |
| let unwrappedResponse = try SwaggerApiResponseHandler.unwrapResponse((successfulResponse, failure)) | |
| result = unwrappedResponse | |
| dispatchGroup.leave() | |
| } catch let error { | |
| outputError = error | |
| dispatchGroup.leave() | |
| } | |
| } | |
| _ = dispatchGroup.wait(wallTimeout: .distantFuture) | |
| if let error = outputError { | |
| throw error | |
| } | |
| if let result = result { | |
| return result | |
| } else { | |
| throw ServiceError.nilData | |
| } | |
| } | |
| class func handleResponse<ResponseType: SequenceApiContainer>(_ response: (successResponse: ResponseType?, failure: Error?), | |
| success: ((ResponseType.T) -> Void), | |
| failure: (Error) -> Void) { | |
| if let error = response.failure { | |
| handleError(error: error) { outputError in | |
| failure(outputError) | |
| } | |
| } else { | |
| if let successResponse = response.successResponse?.data { | |
| success(successResponse) | |
| } else { | |
| let error = NSError(domain: "com.actonica.boomerang.manager", code: -2, userInfo: [NSLocalizedDescriptionKey: "server.error.generic".localized]) | |
| failure(error) | |
| } | |
| } | |
| } | |
| class func handleResponse<ResponseType>(_ response: (successResponse: ResponseType?, failure: Error?), | |
| success: ((ResponseType) -> Void), | |
| failure: (Error) -> Void) { | |
| if let error = response.failure { | |
| handleError(error: error) { outputError in | |
| failure(outputError) | |
| } | |
| } else { | |
| if let successResponse = response.successResponse { | |
| success(successResponse) | |
| } else { | |
| let error = NSError(domain: "com.actonica.boomerang.manager", code: -2, userInfo: [NSLocalizedDescriptionKey: "server.error.generic".localized]) | |
| failure(error) | |
| } | |
| } | |
| } | |
| fileprivate class func handleError(error: Error, failure: (Error) -> Void) { | |
| // Try extract internal error from returned error | |
| switch error { | |
| case let errorResponse as ErrorResponse: | |
| switch errorResponse { | |
| /// code, data, error. in future we can handle different codes. now when internet connection is interrupted error contains info about it, data is empty and code is 500 | |
| case .error(_, let data, let error): | |
| if let data = data, | |
| let serverError = try? JSONDecoder().decode(ErrorBase.self, from: data) { | |
| failure(NSError(domain: "com.actonica.manager::handlerError", code: serverError.errorCode, userInfo: [NSLocalizedDescriptionKey: serverError.failReason ?? ""])) | |
| } else { | |
| failure(error) | |
| } | |
| } | |
| // if web service returned error | |
| default: | |
| failure(error) | |
| } | |
| } | |
| class func unwrapResponse<ResponseType>(_ response: (successResponse: ResponseType?, failure: Error?)) throws -> ResponseType { | |
| if let error = response.failure { | |
| try unwrapError(error: error) | |
| } else { | |
| if let successResponse = response.successResponse { | |
| return successResponse | |
| } | |
| } | |
| let error = NSError(domain: "SwaggerApiResponseHandler::unwrapResponse", code: -2, userInfo: [NSLocalizedDescriptionKey: "server.error.generic".localized]) | |
| throw error | |
| } | |
| class func unwrapError(error: Error) throws { | |
| // Try extract internal error from returned error | |
| switch error { | |
| case let errorResponse as ErrorResponse: | |
| switch errorResponse { | |
| /// code, data, error. in future we can handle different codes. now when internet connection is interrupted error contains info about it, data is empty and code is 500 | |
| case .error(_, let data, let error): | |
| if let data = data, | |
| let serverError = try? JSONDecoder().decode(ErrorBase.self, from: data) { | |
| throw NSError(domain: "SwaggerApiResponseHandler::unwrapError", code: serverError.errorCode, userInfo: [NSLocalizedDescriptionKey: serverError.failReason ?? ""]) | |
| } else { | |
| throw error | |
| } | |
| } | |
| // if web service returned error | |
| default: | |
| throw error | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment