Last active
February 6, 2020 13:23
-
-
Save AndreyAnt/96180d5f78d9d01b5856cd49711d0f90 to your computer and use it in GitHub Desktop.
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
public typealias DecodableError = Error & Decodable | |
// Реактивное расширение, которое позволяет добавить дополнительный парсинг ошибки от сервера, которая приходит обернутой в JSON | |
extension PrimitiveSequence where Trait == RxSwift.SingleTrait, Element == Moya.Response { | |
public func check<DecodableError: Error & Decodable>( | |
for errorType: DecodableError.Type, | |
decoder: JSONDecoder = JSONDecoder() | |
) -> RxSwift.Single<Element> { | |
flatMap { response in | |
do { | |
let error = try decoder.decode(DecodableError.self, from: response.data) | |
return Single.error(error) | |
} catch { | |
return Single.just(response) | |
} | |
} | |
} | |
public func chainCheck<DecodableError: Error & Decodable>( | |
errorTypes: [DecodableError.Type], | |
decoder: JSONDecoder = JSONDecoder() | |
) -> RxSwift.Single<Element> { | |
flatMap { response in | |
let errorChecks = errorTypes.map { self.check(for: $0).asCompletable() } | |
return Completable.concat(errorChecks).andThen(Single.just(response)) | |
} | |
} | |
public func chainCheck2<DecodableError: Error & Decodable>( | |
errorTypes: [DecodableError.Type], | |
decoder: JSONDecoder = JSONDecoder() | |
) -> RxSwift.Single<Element> { | |
if errorTypes.count > 1 { | |
return check(for: errorTypes[0]).flatMap { _ in self.chainCheck(errorTypes: Array(errorTypes.dropFirst())) } | |
} else if errorTypes.count == 1 { | |
return check(for: errorTypes[0]) | |
} | |
preconditionFailure("You can't use chaining function with an empty error types array.") | |
} | |
func chainCheck3( | |
errorTypes: [DecodableError.Type], | |
decoder: JSONDecoder = JSONDecoder() | |
) -> RxSwift.Single<Element> { | |
self.do(onSuccess: { response in | |
try errorTypes.forEach { errorType in | |
decoder.userInfo[DecodableErrorWrapper.typeKey] = errorType | |
guard let wrapped = try? decoder.decode(DecodableErrorWrapper.self, from: response.data) else { return } | |
throw wrapped.error | |
} | |
}) | |
} | |
} | |
private struct DecodableErrorWrapper: Decodable { | |
fileprivate static let typeKey = CodingUserInfoKey(rawValue: "decodableErrorType")! | |
fileprivate let error: DecodableError | |
init(from decoder: Decoder) throws { | |
guard let errorType: DecodableError.Type = decoder.userInfo[DecodableErrorWrapper.typeKey] as? DecodableError.Type else { | |
let description = "Concrete type of DecodableError cannot be recieved from decoder.userInfo. Please check that you are injecting your error type with the correct key!" | |
let context = DecodingError.Context(codingPath: [], debugDescription: description) | |
throw DecodingError.dataCorrupted(context) | |
} | |
self.error = try errorType.init(from: decoder) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment