feat: use DecodingError instead of untyped error in TINetworking decoding
This commit is contained in:
parent
ecfb83bafa
commit
529277d098
|
|
@ -32,7 +32,7 @@ extension StorageKey {
|
|||
let apiTokenKeychainStorage = StringValueKeychainStorage(keychain: keychain, storageKey: .apiToken)
|
||||
|
||||
if apiTokenKeychainStorage.hasStoredValue() {
|
||||
// app wasn't reinstalled, open auth user flow, perform requests
|
||||
// open auth user flow, perform requests
|
||||
} else {
|
||||
// show login screen
|
||||
// ...
|
||||
|
|
|
|||
|
|
@ -33,8 +33,16 @@ open class ApplicationJsonResponseContent<Model: Decodable>: BaseContent, Respon
|
|||
|
||||
// MARK: - ResponseContent
|
||||
|
||||
public func decodeResponse(data: Data) throws -> Model {
|
||||
try jsonDecoder.decode(Model.self, from: data)
|
||||
public func decodeResponse(data: Data) -> Result<Model, DecodingError> {
|
||||
do {
|
||||
return .success(try jsonDecoder.decode(Model.self, from: data))
|
||||
} catch let decodingError as DecodingError {
|
||||
return .failure(decodingError)
|
||||
} catch {
|
||||
return .failure(.dataCorrupted(.init(codingPath: [],
|
||||
debugDescription: .init(),
|
||||
underlyingError: error)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
import Foundation
|
||||
|
||||
public final class EmptyResponseContent: BaseContent, ResponseContent {
|
||||
public func decodeResponse(data: Data) throws {
|
||||
()
|
||||
public func decodeResponse(data: Data) -> Result<Void, DecodingError> {
|
||||
.success(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ import Foundation
|
|||
import TISwiftUtils
|
||||
|
||||
public final class MapResponseContent<Model>: BaseContent, ResponseContent {
|
||||
private let decodeClosure: ThrowableClosure<Data, Model>
|
||||
private let decodeClosure: Closure<Data, Result<Model, DecodingError>>
|
||||
|
||||
public init<C: ResponseContent>(responseContent: C, transform: @escaping Closure<C.Model, Model>) {
|
||||
decodeClosure = {
|
||||
transform(try responseContent.decodeResponse(data: $0))
|
||||
responseContent.decodeResponse(data: $0).map(transform)
|
||||
}
|
||||
|
||||
super.init(mediaTypeName: responseContent.mediaTypeName)
|
||||
|
|
@ -36,8 +36,8 @@ public final class MapResponseContent<Model>: BaseContent, ResponseContent {
|
|||
|
||||
// MARK: - ResponseContent
|
||||
|
||||
public func decodeResponse(data: Data) throws -> Model {
|
||||
try decodeClosure(data)
|
||||
public func decodeResponse(data: Data) -> Result<Model, DecodingError> {
|
||||
decodeClosure(data)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ public extension JSONDecoder {
|
|||
responseContent().map(tranfsorm)
|
||||
}
|
||||
|
||||
func decoding<T: Decodable, R>(to tranfsorm: @escaping Closure<T, R>) -> ThrowableClosure<Data, R> {
|
||||
func decoding<T: Decodable, R>(to tranfsorm: @escaping Closure<T, R>) -> Closure<Data, Result<R, DecodingError>> {
|
||||
responseContent(tranfsorm).decodeResponse
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,5 +25,5 @@ import Foundation
|
|||
public protocol ResponseContent: Content {
|
||||
associatedtype Model
|
||||
|
||||
func decodeResponse(data: Data) throws -> Model
|
||||
func decodeResponse(data: Data) -> Result<Model, DecodingError>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,11 +38,14 @@ public final class TextPlainResponseContent: BaseContent, ResponseContent {
|
|||
|
||||
// MARK: - ResponseContent
|
||||
|
||||
public func decodeResponse(data: Data) throws -> String {
|
||||
public func decodeResponse(data: Data) -> Result<String, DecodingError> {
|
||||
guard let plainText = String(data: data, encoding: encoding) else {
|
||||
throw StringDecodingError(data: data, encoding: encoding)
|
||||
let context = DecodingError.Context(codingPath: [],
|
||||
debugDescription: .init(),
|
||||
underlyingError: StringDecodingError(data: data, encoding: encoding))
|
||||
return .failure(.typeMismatch(String.self, context))
|
||||
}
|
||||
|
||||
return plainText
|
||||
return .success(plainText)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,18 +24,26 @@ import Foundation
|
|||
import TISwiftUtils
|
||||
|
||||
public extension ResponseType {
|
||||
typealias DecodingClosure<R> = ThrowableClosure<Data, R>
|
||||
typealias DecodingClosure<R> = Closure<Data, Result<R, DecodingError>>
|
||||
|
||||
func decode<R>(mapping: [KeyValueTuple<StatusCodeMimeType, DecodingClosure<R>>]) -> Result<R, ErrorType> {
|
||||
var decodingErrors: [DecodingError] = []
|
||||
|
||||
for (statusCodesMimeType, decodeClosure) in mapping
|
||||
where statusCodesMimeType.statusCode == statusCode && statusCodesMimeType.mimeType == mimeType {
|
||||
do {
|
||||
return .success(try decodeClosure(data))
|
||||
} catch {
|
||||
return .failure(objectMappingError(underlyingError: error))
|
||||
switch decodeClosure(data) {
|
||||
case let .success(result):
|
||||
return .success(result)
|
||||
|
||||
case let .failure(decodingError):
|
||||
decodingErrors.append(decodingError)
|
||||
}
|
||||
}
|
||||
|
||||
if let firstDecodingError = decodingErrors.first {
|
||||
return .failure(objectMappingError(underlyingError: firstDecodingError))
|
||||
}
|
||||
|
||||
guard mapping.contains(where: { $0.key.statusCode == statusCode }) else {
|
||||
return .failure(unsupportedStatusCodeError(statusCode: statusCode))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ extension StorageKey {
|
|||
let apiTokenKeychainStorage = StringValueKeychainStorage(keychain: keychain, storageKey: .apiToken)
|
||||
|
||||
if apiTokenKeychainStorage.hasStoredValue() {
|
||||
// app wasn't reinstalled, open auth user flow, perform requests
|
||||
// open auth user flow, perform requests
|
||||
} else {
|
||||
// show login screen
|
||||
// ...
|
||||
|
|
|
|||
Loading…
Reference in New Issue