【问题标题】:Alamofire - How to get API error from AFErrorAlamofire - 如何从 AFError 获取 API 错误
【发布时间】:2021-09-22 00:28:10
【问题描述】:

在我寻求正确实施 Alamofire 5 并处理自定义错误模型响应的过程中,我还没有找到具有示例的公认答案。

为了尽可能彻底,这是我的 apiclient

class APIClient {
    
    static let sessionManager: Session = {
        let configuration = URLSessionConfiguration.af.default
        
        configuration.timeoutIntervalForRequest = 30
        configuration.waitsForConnectivity = true
        
        return Session(configuration: configuration, eventMonitors: [APILogger()])
    }()
    
    @discardableResult
    private static func performRequest<T:Decodable>(route:APIRouter, decoder: JSONDecoder = JSONDecoder(), completion:@escaping (Result<T, AFError>)->Void) -> DataRequest {
            return sessionManager.request(route)
//                .validate(statusCode: 200..<300) // This will kill the server side error response...
                .responseDecodable (decoder: decoder){ (response: DataResponse<T, AFError>) in
                    completion(response.result)
                }
        }
    
    static func login(username: String, password: String, completion:@escaping (Result<User, AFError>)->Void) {
        performRequest(route: APIRouter.login(username: username, password: password), completion: completion)
    }
}

我就是这样用的

APIClient.login(username: "", password: "") { result in
    debugPrint(result)
    switch result {
    case .success(let user):
        debugPrint("__________SUCCESS__________")
    case .failure(let error):
        debugPrint("__________FAILURE__________")
        debugPrint(error.localizedDescription)
    }
}

我注意到如果我使用.validate() 调用函数将收到失败但响应数据丢失。环顾四周,注意到 herehere 转换为 underlyingError 但那是零。

服务器以我在调用函数级别需要的可解析错误模型进行响应。在 apiclient 级别反序列化 JSON 并将其作为失败返回给调用函数会更愉快。

{
    "errorObject": {
        "summary": "",
        "details": [{
            ...
        }]
    }
}

更新

感谢@GIJoeCodes 的评论,我使用路由器实现了这个类似的解决方案。

class APIClient {
    
    static let sessionManager: Session = {
        let configuration = URLSessionConfiguration.af.default
        
        configuration.timeoutIntervalForRequest = 30
        configuration.waitsForConnectivity = true
        
        return Session(configuration: configuration, eventMonitors: [APILogger()])
    }()
    
    @discardableResult
    private static func performRequest<T:Decodable>(route:APIRouter, decoder: JSONDecoder = JSONDecoder(), completion:@escaping (_ response: T?, _ error: Error?)->Void) {
        
        sessionManager.request(route)
            .validate(statusCode: 200..<300) // This will kill the server side error response...
            .validate(contentType: ["application/json"])
            .responseJSON { response in
                
                guard let data = response.data else { return }
                do {
                    switch response.result {
                    case .success:
                        let object = try decoder.decode(T.self, from: data)
                        completion(object, nil)
                        
                    case .failure:
                        let error = try decoder.decode(ErrorWrapper.self, from: data)
                        completion(nil, error.error)
                        
                    }
                } catch {
                    debugPrint(error)
                }
            }
        }
    
    // MARK: - Authentication
    static func login(username: String, password: String, completion:@escaping (_ response: User?, _ error: Error?)->Void) {
        performRequest(route: APIRouter.login(username: username, password: password), completion: completion)
    }
}

这样称呼

APIClient.login(username: "", password: "") { (user, error) in
    if let error = error {
        debugPrint("__________FAILURE__________")
        debugPrint(error)
        return
    }
    
    if let user = user {
        debugPrint("__________SUCCESS__________")
        debugPrint(user)
    }
}

【问题讨论】:

    标签: swift alamofire


    【解决方案1】:

    这就是我获取错误和自定义错误消息的方式。在验证中,我得到了 200..

        AF.request(
            url,
            method: .post,
            parameters: json,
            encoder: JSONParameterEncoder.prettyPrinted,
            headers: headers
        ).validate(statusCode: 200..<300)
        .validate(contentType: ["application/json"])
        .responseJSON { response in
    
            switch response.result {
            case .success(let result):
                let json = JSON(result)
                
                onSuccess()
                
            case .failure(let error):
                
                guard let data = response.data else { return }
    
                do {
                    let json = try JSON(data: data)
                    
                    let message = json["message"]
                    onError(message.rawValue as! String)
    
                } catch {
                    print(error)
                }
                
                onError(error.localizedDescription)
            }
            
            debugPrint(response)
        }
    

    【讨论】:

    • 这可能很好用,但是我正在寻找一个包含路由器的解决方案。我对 swift 和 alamofire 很陌生,似乎基于 .response{type} 的闭包很挑剔,即 responseDecodable、responseJSON 等。尝试在上述结构中切换它,我收到“来自抛出函数的无效转换”。使用 xcode 和 swift 一个多星期,我可能不明白这很简单。
    【解决方案2】:

    首先,如果您已经拥有Decodable 模型,则无需使用responseJSON。通过多次解码响应数据,您正在做不必要的工作。使用responseDecodable 并提供您的Decodable 类型,在本例中为您的通用TresponseDecodable(of: T).

    其次,将预期的Decodable 类型包装在枚举中是解决此问题的典型方法。例如:

    enum APIResponse<T: Decodable> {
      case success(T)
      case failure(APIError)
    }
    

    然后实现APIResponseDecodable尝试解析成功类型或APIError(有很多这样的例子)。然后,您可以使用 responseDecodable(of: APIResponse&lt;T&gt;.self) 解析您的回复。

    【讨论】:

    • 这是我第一次看到 APIResponse 枚举,我花了几天时间寻找解决方案。请提供指向其使用的完整示例的链接。这将是一个更清洁的解决方案。
    • 我能够找到一个文档,其中包含上述枚举的详细信息。 swiftbysundell.com/articles/the-power-of-result-types-in-swift我不明白您所说的“然后实现 APIResponse 的 Decodable 以尝试解析成功的类型或 APIError”是什么意思。看这个文档,有一个解码块,很明显我不明白该怎么做,因为当按照示例实现时,会有很多错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-11
    • 1970-01-01
    • 2021-09-06
    • 2021-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多