Using a Router Enum for URLRequests

This article continues on from a previous article about a Protocol Oriented Programming approach to networking, which is available here. This article is about part of that solution, the Router enum, which is a neater way of creating URLRequests. The whole app is available here.

Use of the Router enum looks like this :

var urlRequest = try Router.testCall.asURLRequest()

testCall is a case of the enum, and represents a particular network call I have to make. URLRequests contain more than just the URL – here my testCall request also contains information about the method the call will use (post, get, delete..), the parameters that will be attached to the call (usually a Dictionary containing for eg, a token), and the encoding method (URLEncoding, JSONEncoding, etc). The Router also builds the path from a base URL, possibly including a passed-in integer or string to customize a path.

The Router can be structured however you like, but the basic idea is that a particular type of call will get its own case. As an example for this demo app, Ive made three cases :

case generalPost([String: Any])
case getUserData(Int)
case deleteSomething(Int)

With the magic of value-binding, we can pass in properties when we use each case, with the properties that we pass in defined in those cases above. So for our generalPost case, a Dictionary of String:Any can be passed in. This could contain token information or other parameters that our web service requires. By the way, this is different to the httpBody property that a URLRequest has, which is where the bulk of a post (or get) is normally attached. The Router doesnt do those – instead they are set on the resulting URLRequest afterwards.

The Router has a single function : asURLRequest. We call this on a case to create the URLRequest. Within that function are several properties which encapsulate what we need :

var method: HTTPMethod { ..
let params: ([String: Any]?) = { ..
let url: URL = { ..
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = method.rawValue
let encoding: ParameterEncoding = {

Usually each of those properties go through all cases, and defines how they should be set for each. I wont go through each one as with a closer look they are fairly self explanatory. But heres one example, also showing how value binding works in practise :

let url: URL = {
    // build up and return the URL for each endpoint
    let relativePath: String?
    switch self {
    case .generalPost:
        relativePath = "generalPostPath"
    case .getUserData(let pathNumber):
        relativePath = "getUserDataPath/\(pathNumber)"
    case .deleteSomething(let pathNumber):
        relativePath = "deleteSomethingPath/\(pathNumber)"
    }
    var url = URL(string: Router.baseURLString)!
    if let relativePath = relativePath {
        url = url.appendingPathComponent(relativePath)
    }
    print("Returning URL: \(url.description)")
    return url
}()

To see the entire Router enum, have a look here.

Leave a Reply

Your email address will not be published. Required fields are marked *