Alamofire icon indicating copy to clipboard operation
Alamofire copied to clipboard

Feature Request: CRUD Router protocol oriented approach

Open initFabian opened this issue 6 years ago • 2 comments

Before submitting a PR, I wanted to ask if the following Routable pattern would fit within the scope of Alamofire and if so, could it be added?

Below you will find a link to the blog post explaining it, along with the example project.

In summary, the blog post uses a different approach to achieve the same goal as the enum Router.

Using Routable, we are able to reduce the example found in Crud & Authorization to the following:

struct Router: URLRouter {
    static var basePath: String {
        return "https://example.com"
    }

    struct User: Readable, Creatable, Updatable, Deletable {
        var route: String = "users"
        var urlParams: String!
    }
}

initFabian avatar Jan 25 '18 17:01 initFabian

An interesting approach. We've discussed different solutions to the huge router problem for a while and haven't yet formalized a solution. I'm currently using this protocol to break the different aspects of the router into types:

public protocol RequestConvertible: URLRequestConvertible {
    var parameters: Parameters? { get }
    var route: Router { get }
}

This allows me to combine a simplified Router (really could just be a separate protocol), which describes the base URL, path, HTTP method, and parameter encoding, from the parameters of a request. RequestConvertible also has a default implementation of asURLRequest():

extension RequestConvertible {
    public func asURLRequest() throws -> URLRequest {
        var url = route.baseURL
        url.appendPathComponent(route.path)
        var request = URLRequest(url: url)
        request.httpMethod = route.method.rawValue
        
        return try route.parameterEncoding.encode(request, with: parameters)
    }
}

This allows me a very simple pattern:

struct LoginRequest {
    let username: String
    let password: String
}

extension LoginRequest: RequestConvertible {
    var parameters: Parameters? {
        return ["username": username,
                "password": password]
    }

   var route: Router {
        return .login
    }
}

To me, this separation of how to make a request vs. what should be in the request allows for a cleaner set of responsibilities than every request type having to implement those values itself. What would be even better here is something to automatically (at least in some cases) generate the parameters to be encoded by the request.

The protocols you've described make a lot of assumptions about how an API works, so I'm not sure they offer the flexibility needed by a library like Alamofire. There isn't always a 1:1 mapping between the action being taken by a call and the HTTP method used to make it (unfortunately), so it doesn't seem like a good idea to encode such ideas into the protocols.

jshier avatar Jan 29 '18 01:01 jshier

@initFabian I have created a library on top of Alamofire Restofire in which every api request is a separate file which makes it very easy to maintain and expand. Though it doesn't solve the router issue but solves the vertical growing of code issue.

rahul0x24 avatar Feb 11 '18 09:02 rahul0x24