Great questions. Let everyone break up every time.
What is the proper use of URLRequestConvertible in the real world API?
The URLRequestConvertible protocol is an easy way to ensure that a given object can create a valid NSURLRequest . In fact, there is no strict set of rules or guidelines that force you to use this protocol in any particular way. This is just a convenient protocol that allows other objects to maintain the state necessary for NSURLRequest to be created NSURLRequest . More information about Alamofire can be found here .
Should I create one router per endpoint?
Definitely not. This will violate the whole purpose of using Enum . Swift Enum objects are surprisingly powerful, which allows you to share a lot of overall state and include parts that are actually different. Ability to create NSURLRequest with something simple than the following, really powerful!
let URLRequest: NSURLRequest = Router.ReadUser("cnoon")
I can’t understand why the enumeration is used to build a router? Why don't we use a class with static methods?
Enumeration is used because it is a much more concise way of expressing several related objects under a common interface. All methods are distributed among all cases. If you used static methods, there must be a static method for each method for each method. Or you will have to use Obj-C style stroke inside the object. Here is a brief example of what I mean.
enum Router: URLRequestConvertible { static let baseURLString = "http://example.com" case CreateUser([String: AnyObject]) case ReadUser(String) case UpdateUser(String, [String: AnyObject]) case DestroyUser(String) var method: Alamofire.Method { switch self { case .CreateUser: return .POST case .ReadUser: return .GET case .UpdateUser: return .PUT case .DestroyUser: return .DELETE } } var path: String { switch self { case .CreateUser: return "/users" case .ReadUser(let username): return "/users/\(username)" case .UpdateUser(let username, _): return "/users/\(username)" case .DestroyUser(let username): return "/users/\(username)" } } }
To get a method from any of the different endpoints, you can call the same method without having to pass any parameters to determine what type of endpoint you are looking for, it is already being processed by the case you selected.
let createUserMethod = Router.CreateUser.method let updateUserMethod = Router.UpdateUser.method
Or, if you want to get the path, the same types of calls.
let updateUserPath = Router.UpdateUser.path let destroyUserPath = Router.DestroyUser.path
Now try using the same approach using static methods.
struct Router: URLRequestConvertible { static let baseURLString = "http://example.com" static var method: Method {
NOTE. If you do not have many properties or functions that include cases, then an enumeration does not provide many advantages over a structure. This is just an alternative approach with different syntactic sugar.
Enumerations can maximize reuse of state and code. Bound values also allow you to do some really powerful things, such as grouping objects that are somewhat similar but have incredibly different requirements ... for example, NSURLRequest creation.
What is the correct way to create parameters for enumerations to improve readability? (had to crush it together)
This is a terrific question. You have already identified two possible options. Let me add a third, which can satisfy your needs a little better.
case CreateUser(username: String, firstName: String, lastName: String, email: String) case ReadUser(username: String) case UpdateUser(username: String, firstName: String, lastName: String, email: String) case DestroyUser(username: String)
In cases where you have related values, I think it may be useful to add explicit names for all the values in the tuple. It really helps build context. The disadvantage is that you have to override these values in switch statements like this.
static var method: String { switch self { case let CreateUser(username: username, firstName: firstName, lastName: lastName, email: email): return "POST" default: return "GET" } }
As long as it gives you a pleasant, consistent context, it becomes quite verbose. These are your three options at the moment in Swift, which one to use depends on your use case.
Update
With the release of 🔥🔥 Alamofire 4.0 🔥🔥, URLRequestConvertible can now be much smarter and can also throw. We have added full Alamofire support for handling invalid requests and creating reasonable errors using response handlers. This new system is described in detail in our README .