Пользовательская ошибка проверки больше не работает в Alamofire 5
Используя Alamofire 4, у нас был валидатор ответов API, который мы вызывали следующим образом:
func request<Endpoint: APIEndpoint>(_ baseURL: URL, endpoint: Endpoint, completion: @escaping (_ object: Endpoint.ResponseType?, _ error: AFError?) -> Void) -> DataRequest where Endpoint.ResponseType: Codable {
let responseSerializer = APIObjectResponseSerializer(endpoint)
let request = self.request(baseURL, endpoint: endpoint)
.validate(APIResponseValidator.validate) << VALIDATOR PASSED HERE
.response(responseSerializer: responseSerializer) { response in
completion(response.value, response.error)
}
return request
}
Выглядит это так:
static func validate(request: URLRequest?, response: HTTPURLResponse, data: Data?) -> Request.ValidationResult {
// **INSERT OTHER FAILURE CHECKS HERE**
// Verify server time is within a valid time window.
let headers = response.allHeaderFields
guard let serverTimeString = headers["Date"] as? String, let serverTime = DateUtils.headerDateFormatter().date(from: serverTimeString) else {
Log.error("APIValidation: no Date in response header")
return .failure(APIError.appTimeSettingInvalid))
}
// **INSERT OTHER FAILURE CHECKS HERE**
return .success(Void())
}
Соответствующая ошибка вернется в обработчик завершения запроса,
▿ APIError
▿ appTimeSettingInvalid
и мы могли обновить пользовательский интерфейс с правильной ошибкой, все были довольны.
Но теперь с Alamofire это следующее:
▿ Optional<Error>
▿ some : AFError
▿ requestRetryFailed : 2 elements
▿ retryError : AFError
▿ responseValidationFailed : 1 element
▿ reason : ResponseValidationFailureReason
▿ customValidationFailed : 1 element
▿ error : APIError
▿ appTimeSettingInvalid << Original custom error
▿ originalError : AFError
▿ responseValidationFailed : 1 element
▿ reason : ResponseValidationFailureReason
▿ customValidationFailed : 1 element
▿ error : APIError
▿ appTimeSettingInvalid << Original custom error
К чему мне нужно получить доступ вот так:
if let underlyingError = (error as? AFError)?.underlyingError as? AFError,
case let AFError.requestRetryFailed(_, originalError) = underlyingError,
case let AFError.responseValidationFailed(reason) = originalError,
case let .customValidationFailed(initialCustomError) = reason {
showAlert(initialCustomError)
}
Это кажется абсурдным. Что мне не хватает? Почему пользовательская проверка завершилась неудачно, если в методе ничего не изменилось, и почему он заключен в слой других ошибок? Зачем повторять запрос, если проверка не удастся точно так же?
Как мне последовательно возвращать мою пользовательскую ошибку во всех моих запросах?
2 ответа
В Alamofire 5 все ошибки возвращаются, содержащиеся в AFError
экземпляр, включая пользовательские ошибки проверки. Это позволяет нашимResponse
типы, содержащие типизированные ошибки и обеспечивающие согласованный тип ошибки. Однако API проверки по-прежнему возвращаетError
экземпляров, к сожалению, поэтому есть дополнительный слой, который нужно отклеить. Вы можете использовать удобствоasAFError
свойство для выполнения приведения и underlyingError
свойство, чтобы захватить любые основные ошибки. Использованиеswitch
операторы также могут облегчить извлечение. Вы также можетеmapError
в ответах для извлечения нужных вам типов ошибок.
Что касается повтора, вероятно, ваш retrier не был обновлен для извлечения ошибок таким образом, чтобы повторные попытки должным образом избегались с вашим пользовательским типом ошибки.
Пример кода для преобразования AFError в обычную пользовательскую ошибку:
Как обычно, используйте переключатель типа результата, затем при ошибке:
{ (result) in
switch result {
case .success(_, _, _):
,.............
case .failure(let error):
let afError = error.asAFError?.underlyingError ?? error
completion(afError)
asAFError?.underlyingError доступен в среде Alomafire.