Routing Parameters¶
Traditional web frameworks leave room for error in routing by using strings for route parameter names and types. Vapor takes advantage of Swift's closures to provide a safer and more intuitive method for accessing route parameters.
Seealso
Route parameters refer to segments of the URL path (e.g., /users/:id
). For query parameters (e.g., ?foo=bar
) see request query parameters.
Type Safe¶
To create a type safe route simply replace one of the parts of your path with a Type
.
drop.get("users", Int.parameter) { req in let userId = try req.parameters.next(Int.self) return "You requested User #\(userId)" }
This creates a route that matches users/:id
where the :id
is an Int
. Here's what it would look like using manual route parameters.
drop.get("users", ":id") { request in guard let userId = request.parameters["id"]?.int else { throw Abort.badRequest } return "You requested User #\(userId)" }
Here you can see that type safe routing saves ~3 lines of code and also prevents runtime errors like misspelling :id
.
Parameterizable¶
Any type conforming to Parameterizable
can be used as a parameter. By default, all Vapor Models conform.
Using this, our previous example with users can be further simplified.
drop.get("users", User.parameter) { req in let user = try req.parameters.next(User.self) return "You requested \(user.name)" }
Here the identifier supplied is automatically used to lookup a user. For example, if /users/5
is requested, the User
model will be asked for a user with identifier 5
. If one is found, the request succeeds and the closure is called. If not, a not found error is thrown.
Here is what this would look like if we looked the model up manually.
drop.get("users", Int.parameter) { req in let userId = try req.parameters.next(Int.self) guard let user = try User.find(userId) else { throw Abort.notFound } return "You requested \(user.name)" }
Protocol¶
You can conform your own types to Parameterizable
.
import Routing extension Foo: Parameterizable { /// This unique slug is used to identify /// the parameter in the router static var uniqueSlug: String { return "foo" } static func make(for parameter: String) throws -> Foo { /// custom lookup logic here /// the parameter string contains the information /// parsed from the URL. ... } }
Now you can use this type for type safe routing.
drop.get("users", "nickname", Foo.parameter) { req in let foo = try req.parameters.next(Foo.self) ... }
Groups¶
Type-safe parameters also work with groups.
let userGroup = drop.grouped("users", User.parameter) userGroup.get("messages") { req in let user = try req.parameters.next(User.self) ... }