如何实现具有类似 asURLRequest() 的多个路由器

Posted

技术标签:

【中文标题】如何实现具有类似 asURLRequest() 的多个路由器【英文标题】:How to implement multiple Routers with similar asURLRequest() 【发布时间】:2021-09-23 19:42:32 【问题描述】:

我一直在努力在我们的应用程序中重新实现一个健康的网络层,并且在许多教程/Alamofire 文档中都提到了路由器。该应用程序有很多端点,为了保持可读性,我想将它们分成它们的服务子集。这也被认为是一种最佳做法。

我实现的第一个端点工作得非常好,但是,当我创建另一个路由器时,asURLRequest() 函数几乎是重复的。唯一的区别可能是开关/外壳。否则几乎可以肯定是一样的。

要在 Kotlin 或 Java 中执行此操作,我将创建一个类并扩展调用 super 的函数。我不确定这在 Swift 中是如何工作的。

enum AuthenticationRouter: URLRequestConvertible 
    
    case login(username:String, password:String)
    
    // MARK: - HTTPMethod
    private var method: HTTPMethod 
        switch self 
        case .login:
            return .get
        
    
    
    // MARK: - Path
    private var path: String 
        switch self 
        case .login:
            return "users/login"
        
    
    
    // MARK: - Parameters
    private var parameters: Parameters? 
        switch self 
        case .login:
            return nil
        
    
    
    // MARK: - URLRequestConvertible
    func asURLRequest() throws -> URLRequest 
        let url = try K.TestServer.baseURL.asURL()
        
        var urlRequest = URLRequest(url: url.appendingPathComponent(path))
        
        // HTTP Method
        urlRequest.httpMethod = method.rawValue
        
        // Common Headers
        urlRequest.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.acceptType.rawValue)
        urlRequest.setValue(ContentType.json.rawValue, forHTTPHeaderField: HTTPHeaderField.contentType.rawValue)
        
        switch self 
        case .login(let username, let password):
            // Handle adjusting headers or request as needed
        default: ()
        
        
        // Parameters
        if let parameters = parameters 
            do 
                urlRequest.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])
             catch 
                throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
            
        
        
        return urlRequest
    

【问题讨论】:

如何使用继承/协议?创建实现 asUrlRequest() 函数的基本路由器类/协议?每个其他路由器都有自己的参数/符合 Alamofire 协议的其他部分 【参考方案1】:

这是我使用的旧代码。我会将基类更改为协议,并继续使用符合该协议的枚举,我更喜欢它。

import Alamofire

protocol API 
    var method: HTTPMethod  get 
    var encoding: ParameterEncoding?  get 
    var parameters: Parameters  get 
    var headers: HTTPHeaders  get 
    var timeout:TimeInterval  get 
    var path: String  get 
    var baseUrl: String  get 


class Router: API 
    var method: HTTPMethod  .get 

    var encoding: ParameterEncoding?  JSONEncoding.default 

    var parameters: Parameters 
        let params = Parameters()
        return params
    

    var headers: HTTPHeaders 
        let headers = HTTPHeaders()
        // TODO - add defualt headers if needed
        return headers
    

    var timeout: TimeInterval 
        #if DEBUG
            return 120
        #else
            return 30
        #endif
    

    var path: String 
        fatalError("Must be overridden in subclass")
    

    var baseUrl: String  Consts.serverUrl 



extension Router: URLRequestConvertible 
    open func asURLRequest() throws -> URLRequest 
        guard let baseURL = URL(string: baseUrl) else  throw someError 
    
        let appendedURL = baseURL.appendingPathComponent(path)
        let urlRequest = try URLRequest(url: appendedURL, method: method)
    
        guard let encoder = encoding else  throw someError 
    
        var eUrlRequest = try encoder.encode(urlRequest, with: parameters)
        eUrlRequest.timeoutInterval = timeout
        headers.forEach  eUrlRequest.addValue($0.value, forHTTPHeaderField: $0.name) 
        return eUrlRequest
    

然后是 UserRouter 的示例

import Alamofire

final class UserRouter: Router 

    enum Endpoint 
        case signIn(userName: String, password: String)
    

    let endpoint: Endpoint

    init(endpoint: Endpoint) 
        self.endpoint = endpoint
    

    override var method: HTTPMethod 
        .get
    

    override var parameters: Parameters 
        var params = super.parameters
        switch endpoint 
        case .signIn(let userName, let password): 
            params[“login”] = [“username”: userName, “password”: password]
        
        return params
    

    override var path: String 
        switch endpoint 
        case .signIn:
            return "/signIn"
        
    

这样,asUrlRequest() 函数将在整个代码中使用(;Alamofire.Session().request() 函数将接受每个路由器。

此外,还有一个很棒的开源抽象可以在 Alamofire 上进行类似的工作。莫亚-https://github.com/Moya/Moya。 它开箱即用地支持 Combine 和 RxSwift

【讨论】:

以上是关于如何实现具有类似 asURLRequest() 的多个路由器的主要内容,如果未能解决你的问题,请参考以下文章

如何在 maximo 中隐藏具有类似于银行帐号的特殊字符的字段值

如何在颤动中创建具有多行的行

vb6中如何实现类似MDI子窗体的窗体

哪些 SQL 实现具有类似 PSM 的功能?

如何正确处理情节提要中的类似视图,这些视图具有类似的控制器而无需重复代码?

如何让jquery mobile listview(或类似的)具有多列