Skip to content

Instantly share code, notes, and snippets.

@AndreyAnt
Last active February 6, 2020 13:23
Show Gist options
  • Save AndreyAnt/96180d5f78d9d01b5856cd49711d0f90 to your computer and use it in GitHub Desktop.
Save AndreyAnt/96180d5f78d9d01b5856cd49711d0f90 to your computer and use it in GitHub Desktop.
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