如何使用Alamofire Router来组织API调用?(swift Alamofire5)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用Alamofire Router来组织API调用?(swift Alamofire5)相关的知识,希望对你有一定的参考价值。

我想把我的 AF请求路由器 结构,使项目更简洁。我收到一个错误信息

协议类型'Any'的值不能符合'Encodable';只有structenumclass类型才能符合协议。

请帮我修正一下代码。THANK YOU!

我的URL将有一个占位符为 帐号密码 将被送入 body. 答复将是: Bool (success), username and bearer token.

下面是我的 AF请求:

let username = usernameTextField.text
let password = passwordTextField.text
let loginParams = ["password":"\(password)"]

AF.request("https://example.com/users/\(username)/login", 
            method: .post, 
            parameters: loginParams, 
            encoder: JSONParameterEncoder.default, 
            headers: nil, interceptor: nil).response  response in

                switch response.result 
                case .success:
                    if let data = response.data 

                        do 
                            let userLogin = try JSONDecoder().decode(UsersLogin.self, from: data)

                            if userLogin.success == true 
                                defaults.set(username, forKey: "username")
                                defaults.set(password, forKey: "password")
                                defaults.set(userLogin.token, forKey: "token")
                                print("Successfully get token.")

                             else 
                                //show alert
                                print("Failed to get token with incorrect login info.")
                            
                         catch 
                            print("Error: \(error)")
                        
                    

                case .failure(let error):
                    //show alert
                    print("Failed to get token.")
                    print(error.errorDescription as Any)
                
            

到目前为止,我有什么可以转换为 AF路由器 结构。

import Foundation
import Alamofire

enum Router: URLRequestConvertible 
    case login(username: String, password: String)

    var method: HTTPMethod 
        switch self 
        case .login:
            return .post
        
    

    var path: String 
        switch self 
        case .login(let username):
            return "/users/\(username)/login"
        
    

    var parameters: Parameters? 
        switch self 
        case .login(let password):
            return ["password": password]

        
    

    // MARK: - URLRequestConvertible
    func asURLRequest() throws -> URLRequest 
        let url = try Constants.ProductionServer.baseURL.asURL()
        var request = URLRequest(url: url.appendingPathComponent(path))

        // HTTP Method
        request.httpMethod = method.rawValue

        // Common Headers
        request.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.acceptType.rawValue)
        request.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.contentType.rawValue)

        // Parameters
        switch self 
        case .login(let password):
            request = try JSONParameterEncoder().encode(parameters, into: request) //where I got the error
        

        return request
    


class APIClient 
        static func login(password: String, username: String, completion: @escaping (Result<UsersLogin, AFError>) -> Void) 
            AF.request(Router.login(username: username, password: password)).responseDecodable  (response: DataResponse<UsersLogin, AFError>) in
                completion(response.result)
            
        
    

LoginViewController 类(我替换了AF.request代码)

APIClient.login(password: password, username: username)  result in
                    switch result 
                    case .success(let user):
                        print(user)
                    case .failure(let error):
                        print(error.localizedDescription)
                    

可编码 UsersLogin 模型

struct UsersLogin: Codable 
    let success: Bool
    let username: String
    let token: String?

    enum CodingKeys: String, CodingKey 
        case success = "success"
        case username = "username"
        case token = "token"
    

答案

你不能使用 Parameters 词典中带有 Encodable 类型的字典,作为 [String: Encodable] 不是 Encodable,就像错误说的那样。我建议把这一步移到 asURLRequest 流程中的一个单独的函数,比如。

func encodeParameters(into request: inout URLRequest) 
    switch self 
    case let .login(parameters):
        request = try JSONParameterEncoder().encode(parameters, into: request)
    

不幸的是,对于有很多路由的路由器来说,这并不能很好地扩展, 所以我通常把我的路由分解成小的枚举, 然后把我的参数移到单独的类型中, 再和路由器结合起来,从而产生 URLRequest.

另一答案

我花了点时间,但终于把它修好了。我也清理了一下代码。

enum Router: URLRequestConvertible 
    case login([String: String], String) 

    var baseURL: URL 
        return URL(string: "https://example.com")!
    

    var method: HTTPMethod 
        switch self 
        case .login:
            return .post
        
    

    var path: String 
        switch self 
        case .login(_, let username):
            return "/users/\(username)/login"
        
    

    func asURLRequest() throws -> URLRequest 
        print(path)
        let urlString = baseURL.appendingPathComponent(path).absoluteString.removingPercentEncoding!
        let url = URL(string: urlString)
        var request = URLRequest(url: url!)
        request.method = method

        switch self 
        case let .login(parameters, _):
            request = try JSONParameterEncoder().encode(parameters, into: request)
        

        return request
    

使用方法

let username = usernameTextField.text

AF.request(Router.login(["password": password], username)).responseDecodable(of: UsersLogin.self)  (response) in

   if let userLogin = response.value 
      switch userLogin.success 
      case true:
           print("Successfully get token.")
      case false:
           print("Failed to get token with incorrect login info.")
      
    else 
      print("Failed to get token.")
   

以上是关于如何使用Alamofire Router来组织API调用?(swift Alamofire5)的主要内容,如果未能解决你的问题,请参考以下文章

api请求失败时如何在swift alamofire中使用responsedecodable解析错误

如何用 redux 和 react-router 组织状态?

无线路由器ap模式和router模式有啥区别

iOS项目开发MVVM架构实践(第一篇:Router协议)

Alamofire:取消(暂停)文件上传

使用 Alamofire 2.0 请求失败