首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用Alamofire路由器来组织API调用?[swift/ Alamofire5]

如何使用Alamofire路由器来组织API调用?[swift/ Alamofire5]
EN

Stack Overflow用户
提问于 2020-05-15 21:33:48
回答 3查看 1.6K关注 0票数 0

我正在尝试将我的AF请求转换为路由器结构,以获得更干净的项目。我收到了一个错误:

协议类型'Any‘的值不能符合'Encodable';只有struct/enum/class类型才能符合协议。

请帮我修一下密码。谢谢!

我的URL将有一个用户名的占位符,密码将在body中发送。响应将是Bool (success), username and bearer token

下面是我的AF请求

代码语言:javascript
复制
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路由器结构,我有以下内容:

代码语言:javascript
复制
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代码)

代码语言:javascript
复制
APIClient.login(password: password, username: username) { result in
                    switch result {
                    case .success(let user):
                        print(user)
                    case .failure(let error):
                        print(error.localizedDescription)
                    }

可编编码UsersLogin模型

代码语言:javascript
复制
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"
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-05-27 20:27:35

花了我一段时间但终于修好了。我也清理了代码。

代码语言:javascript
复制
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
    }
}

用法

代码语言:javascript
复制
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.")
   }
}
票数 1
EN

Stack Overflow用户

发布于 2021-11-12 11:56:31

我用这种方式解决了一个类似的问题。我创建了一个协议Routable

代码语言:javascript
复制
enum EncodeMode {
    case encoding(parameterEncoding: ParameterEncoding, parameters: Parameters?)
    case encoder(parameterEncoder: ParameterEncoder, parameter: Encodable)
}

protocol Routeable: URLRequestConvertible {
    
    var baseURL: URL { get }
    var path: String { get }
    var method: HTTPMethod { get }
    var encodeMode: EncodeMode { get }
}

extension Routeable {
    
    // MARK: - URLRequestConvertible
    
    func asURLRequest() throws -> URLRequest {
        let url = baseURL.appendingPathComponent(path)
        var urlRequest: URLRequest
        
        switch encodeMode {
        case .encoding(let parameterEncoding, let parameters):
            urlRequest = try parameterEncoding.encode(URLRequest(url: url), with: parameters)
        case .encoder(let parameterEncoder, let parameter):
            urlRequest = URLRequest(url: url)
            urlRequest = try parameterEncoder.encode(AnyEncodable(parameter), into: urlRequest)
        }

        urlRequest.method = method
        return urlRequest
    }
}

我的路由器看起来就像这个

代码语言:javascript
复制
enum WifiInterfacesRouter: Routeable {
    
    case listActive(installationId: Int16?)
    case insert(interface: WifiInterface)
    
    var encodeMode: EncodeMode {
        
        switch self {
        case .listActive(let installationId):
            guard let installationId = installationId else {
                return .encoding(parameterEncoding: URLEncoding.default, parameters: nil)
            }
            return .encoding(parameterEncoding: URLEncoding.default, parameters: ["idInstallation": installationId])
        case .insert(let interface):
            return .encoder(parameterEncoder: JSONParameterEncoder.default, parameter: interface)
        }
        
    }
    
    var baseURL: URL {
        return URL(string: "www.example.com/wifiInterfaces")!
    }
    
    var method: HTTPMethod {
        switch self {
        case .listActive: return .get
        case .insert: return .post
        }
    }
    
    var path: String {
        switch self {
        case .listActive: return "listActive"
        case .insert: return "manage"
        }
    }
}

解决构建错误

协议'Encodable‘作为一种类型不能符合协议本身

我使用了有用的AnyCodable库。Codable的类型擦除实现。

票数 1
EN

Stack Overflow用户

发布于 2020-05-18 17:36:07

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

代码语言:javascript
复制
func encodeParameters(into request: inout URLRequest) {
    switch self {
    case let .login(parameters):
        request = try JSONParameterEncoder().encode(parameters, into: request)
    }
}

不幸的是,对于有许多路由的路由器来说,这不是很好,所以我通常将我的路由分解成小枚举,并将参数移动到与路由器结合生成URLRequest的不同类型中。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61828715

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档