refactor: use default server from network service, simplify recoverable requests
This commit is contained in:
parent
b52dd87f55
commit
b42fcd596f
|
|
@ -35,11 +35,14 @@ open class DefaultJsonNetworkService {
|
|||
public var jsonDecoder: JSONDecoder
|
||||
public var jsonEncoder: JSONEncoder
|
||||
|
||||
public var defaultServer: Server
|
||||
|
||||
public var plugins: [PluginType] = []
|
||||
|
||||
public init(session: Session,
|
||||
jsonDecoder: JSONDecoder,
|
||||
jsonEncoder: JSONEncoder,
|
||||
defaultServer: Server,
|
||||
serializationQueue: DispatchQueue = .global(qos: .default),
|
||||
callbackQueue: DispatchQueue = .main) {
|
||||
|
||||
|
|
@ -48,6 +51,7 @@ open class DefaultJsonNetworkService {
|
|||
self.callbackQueue = callbackQueue
|
||||
self.jsonDecoder = jsonDecoder
|
||||
self.jsonEncoder = jsonEncoder
|
||||
self.defaultServer = defaultServer
|
||||
}
|
||||
|
||||
open func createProvider() -> MoyaProvider<SerializedRequest> {
|
||||
|
|
@ -101,14 +105,15 @@ open class DefaultJsonNetworkService {
|
|||
mapMoyaError: @escaping Closure<MoyaError, R>,
|
||||
completion: @escaping ParameterClosure<R>) -> Cancellable {
|
||||
|
||||
ScopeCancellable { [jsonEncoder, serializationQueue, callbackQueue] scope in
|
||||
ScopeCancellable { [jsonEncoder, serializationQueue, callbackQueue, defaultServer] scope in
|
||||
let workItem = DispatchWorkItem {
|
||||
guard !scope.isCancelled else {
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let serializedRequest = try request.serialize(using: ApplicationJsonBodySerializer(jsonEncoder: jsonEncoder))
|
||||
let serializedRequest = try request.serialize(using: ApplicationJsonBodySerializer(jsonEncoder: jsonEncoder),
|
||||
defaultServer: defaultServer)
|
||||
|
||||
scope.add(cancellable: self.process(request: serializedRequest,
|
||||
decodableSuccessStatusCodes: decodableSuccessStatusCodes,
|
||||
|
|
|
|||
|
|
@ -30,41 +30,33 @@ open class DefaultRecoverableJsonNetworkService<ApiError: Decodable & Error>: De
|
|||
|
||||
private var defaultErrorHandlers: [ErrorHandler] = []
|
||||
|
||||
public func process<RF: RequestFactory>(recoverableRequest: RF,
|
||||
prependErrorHandlers: [ErrorHandler] = [],
|
||||
appendErrorHandlers: [ErrorHandler] = [],
|
||||
mapMoyaError: @escaping Closure<MoyaError, ApiError>) async -> Result<RF.SuccessResponse, ApiError> where RF.Body: Encodable, RF.SuccessResponse: Decodable, RF.CreateFailure == ApiError {
|
||||
public func process<B: Encodable, S: Decodable>(request: EndpointRequest<B, S>,
|
||||
prependErrorHandlers: [ErrorHandler] = [],
|
||||
appendErrorHandlers: [ErrorHandler] = [],
|
||||
mapMoyaError: @escaping Closure<MoyaError, ApiError>) async -> Result<S, ApiError> {
|
||||
|
||||
await process(recoverableRequest: recoverableRequest,
|
||||
await process(request: request,
|
||||
errorHandlers: prependErrorHandlers + defaultErrorHandlers + appendErrorHandlers,
|
||||
mapMoyaError: mapMoyaError)
|
||||
}
|
||||
|
||||
public func process<RF: RequestFactory>(recoverableRequest: RF,
|
||||
errorHandlers: [ErrorHandler] = [],
|
||||
mapMoyaError: @escaping Closure<MoyaError, ApiError>) async -> Result<RF.SuccessResponse, ApiError> where RF.Body: Encodable, RF.SuccessResponse: Decodable, RF.CreateFailure == ApiError {
|
||||
public func process<B: Encodable, S: Decodable>(request: EndpointRequest<B, S>,
|
||||
errorHandlers: [ErrorHandler] = [],
|
||||
mapMoyaError: @escaping Closure<MoyaError, ApiError>) async -> Result<S, ApiError> {
|
||||
|
||||
switch recoverableRequest.create() {
|
||||
case let .success(endpointRequest):
|
||||
let result = await process(request: endpointRequest, mapMoyaError: mapMoyaError) as Result<RF.SuccessResponse, ApiError>
|
||||
let result = await process(request: request, mapMoyaError: mapMoyaError)
|
||||
|
||||
switch result {
|
||||
case let .failure(errorResponse):
|
||||
let chain = AsyncEventHandlingChain(handlers: errorHandlers)
|
||||
if case let .failure(errorResponse) = result {
|
||||
let chain = AsyncEventHandlingChain(handlers: errorHandlers)
|
||||
|
||||
if await chain.handle(errorResponse) {
|
||||
return await process(recoverableRequest: recoverableRequest,
|
||||
errorHandlers: errorHandlers,
|
||||
mapMoyaError: mapMoyaError)
|
||||
} else {
|
||||
return result
|
||||
}
|
||||
default:
|
||||
return result
|
||||
if await chain.handle(errorResponse) {
|
||||
return await process(request: request,
|
||||
errorHandlers: errorHandlers,
|
||||
mapMoyaError: mapMoyaError)
|
||||
}
|
||||
case let .failure(error):
|
||||
return .failure(error)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
public func register<ErrorHandler: AsyncErrorHandler>(defaultErrorHandler: ErrorHandler) where ErrorHandler.EventType == ApiError {
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2022 Touch Instinct
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import TINetworking
|
||||
|
||||
public protocol RequestFactory {
|
||||
associatedtype Body
|
||||
associatedtype SuccessResponse
|
||||
associatedtype CreateFailure: Error
|
||||
|
||||
func create() -> Result<EndpointRequest<Body, SuccessResponse>, CreateFailure>
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2022 Touch Instinct
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the Software), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
import TINetworking
|
||||
|
||||
public struct StaticRequestFactory<Body, SuccessResponse, CreateFailure: Error>: RequestFactory {
|
||||
let request: EndpointRequest<Body, SuccessResponse>
|
||||
|
||||
public init(request: EndpointRequest<Body, SuccessResponse>) {
|
||||
self.request = request
|
||||
}
|
||||
|
||||
public func create() -> Result<EndpointRequest<Body, SuccessResponse>, CreateFailure> {
|
||||
.success(request)
|
||||
}
|
||||
}
|
||||
|
||||
public extension EndpointRequest {
|
||||
func staticRequestFactory<CreateFailure: Error>() -> StaticRequestFactory<Body, SuccessResponse, CreateFailure> {
|
||||
.init(request: self)
|
||||
}
|
||||
}
|
||||
|
|
@ -24,8 +24,10 @@ import Alamofire
|
|||
import Foundation
|
||||
|
||||
public extension EndpointRequest {
|
||||
func serialize<Serializer: BodySerializer>(using serializer: Serializer) throws -> SerializedRequest where Serializer.Body == Body {
|
||||
let baseUrl = try server.url(using: customServerVariables)
|
||||
func serialize<Serializer: BodySerializer>(using serializer: Serializer,
|
||||
defaultServer: Server) throws -> SerializedRequest where Serializer.Body == Body {
|
||||
|
||||
let baseUrl = try (server ?? defaultServer).url(using: customServerVariables)
|
||||
let path = PathParameterEncoding(templateUrl: templatePath).encode(parameters: pathParameters)
|
||||
let (contentType, bodyData) = try serializer.serialize(body: body)
|
||||
let queryParameters = QueryStringParameterEncoding().encode(parameters: queryParameters)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public struct EndpointRequest<Body, SuccessResponse> {
|
|||
public var headerParameters: HTTPHeaders?
|
||||
public var cookieParameters: [String: Parameter<LocationCookie>]
|
||||
public var acceptableStatusCodes: Set<Int>
|
||||
public var server: Server
|
||||
public var server: Server?
|
||||
public var customServerVariables: [KeyValueTuple<String, String>]
|
||||
|
||||
public init(templatePath: String,
|
||||
|
|
@ -42,7 +42,7 @@ public struct EndpointRequest<Body, SuccessResponse> {
|
|||
headerParameters: HTTPHeaders? = nil,
|
||||
cookieParameters: [String: Parameter<LocationCookie>] = [:],
|
||||
acceptableStatusCodes: Set<Int> = HTTPCodes.success.asSet(),
|
||||
server: Server,
|
||||
server: Server? = nil,
|
||||
customServerVariables: [KeyValueTuple<String, String>] = []) {
|
||||
|
||||
self.templatePath = templatePath
|
||||
|
|
|
|||
Loading…
Reference in New Issue