vapor-docs/2.0/docs/routing/parameters.md

107 lines
2.9 KiB
Markdown

# 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](../http/request#query-parameters).
## Type Safe
To create a type safe route simply replace one of the parts of your path with a `Type`.
```swift
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.
```swift
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](../fluent/model.md) conform.
Using this, our previous example with users can be further simplified.
```swift
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.
```swift
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`.
```swift
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.
```swift
drop.get("users", "nickname", Foo.parameter) { req in
let foo = try req.parameters.next(Foo.self)
...
}
```
### Groups
Type-safe parameters also work with [groups](group.md).
```swift
let userGroup = drop.grouped("users", User.parameter)
userGroup.get("messages") { req in
let user = try req.parameters.next(User.self)
...
}
```