2.9 KiB
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)
...
}