mirror of https://github.com/rwf2/Rocket.git
Various guide updates for 0.3.
This commit is contained in:
parent
ed14f59c44
commit
1c866f34fa
|
@ -3,8 +3,8 @@
|
||||||
Welcome to Rocket!
|
Welcome to Rocket!
|
||||||
|
|
||||||
This is the official guide. It is designed to serve as a starting point to
|
This is the official guide. It is designed to serve as a starting point to
|
||||||
writing web application with Rocket and Rust. The guide is also designed to be a
|
writing web applications with Rocket and Rust. The guide is also designed to be
|
||||||
reference for experienced Rocket developers. This guide is conversational in
|
a reference for experienced Rocket developers. This guide is conversational in
|
||||||
tone. For concise and purely technical documentation, see the [API
|
tone. For concise and purely technical documentation, see the [API
|
||||||
documentation](https://api.rocket.rs).
|
documentation](https://api.rocket.rs).
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ aspect of Rocket. The sections are:
|
||||||
parsing, and validating.
|
parsing, and validating.
|
||||||
- **[Responses](responses/):** discusses generating responses.
|
- **[Responses](responses/):** discusses generating responses.
|
||||||
- **[State](state/):** how to manage state in a Rocket application.
|
- **[State](state/):** how to manage state in a Rocket application.
|
||||||
- **[Fairings](fairings/):** introduction to Rocket's structure middleware.
|
- **[Fairings](fairings/):** provides an overview of Rocket's structured
|
||||||
|
middleware.
|
||||||
- **[Testing](testing/):** how to unit and integration test a Rocket
|
- **[Testing](testing/):** how to unit and integration test a Rocket
|
||||||
application.
|
application.
|
||||||
- **[Configuration](configuration/):** how to configure a Rocket application.
|
- **[Configuration](configuration/):** how to configure a Rocket application.
|
||||||
|
|
|
@ -63,7 +63,7 @@ value:
|
||||||
[development]
|
[development]
|
||||||
address = "localhost"
|
address = "localhost"
|
||||||
port = 8000
|
port = 8000
|
||||||
workers = [number_of_cpus * 2]
|
workers = [number of cpus * 2]
|
||||||
log = "normal"
|
log = "normal"
|
||||||
secret_key = [randomly generated at launch]
|
secret_key = [randomly generated at launch]
|
||||||
limits = { forms = 32768 }
|
limits = { forms = 32768 }
|
||||||
|
@ -71,7 +71,7 @@ limits = { forms = 32768 }
|
||||||
[staging]
|
[staging]
|
||||||
address = "0.0.0.0"
|
address = "0.0.0.0"
|
||||||
port = 80
|
port = 80
|
||||||
workers = [number_of_cpus * 2]
|
workers = [number of cpus * 2]
|
||||||
log = "normal"
|
log = "normal"
|
||||||
secret_key = [randomly generated at launch]
|
secret_key = [randomly generated at launch]
|
||||||
limits = { forms = 32768 }
|
limits = { forms = 32768 }
|
||||||
|
@ -79,7 +79,7 @@ limits = { forms = 32768 }
|
||||||
[production]
|
[production]
|
||||||
address = "0.0.0.0"
|
address = "0.0.0.0"
|
||||||
port = 80
|
port = 80
|
||||||
workers = [number_of_cpus * 2]
|
workers = [number of cpus * 2]
|
||||||
log = "critical"
|
log = "critical"
|
||||||
secret_key = [randomly generated at launch]
|
secret_key = [randomly generated at launch]
|
||||||
limits = { forms = 32768 }
|
limits = { forms = 32768 }
|
||||||
|
@ -98,7 +98,7 @@ overrides if already present, that parameter in every environment. For example,
|
||||||
given the following `Rocket.toml` file, the value of `address` will be
|
given the following `Rocket.toml` file, the value of `address` will be
|
||||||
`"1.2.3.4"` in every environment:
|
`"1.2.3.4"` in every environment:
|
||||||
|
|
||||||
```toml
|
```
|
||||||
[global]
|
[global]
|
||||||
address = "1.2.3.4"
|
address = "1.2.3.4"
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ application, can use them as they wish. As an example, the
|
||||||
accepts a value for the `template_dir` configuration parameter. The parameter
|
accepts a value for the `template_dir` configuration parameter. The parameter
|
||||||
can be set in `Rocket.toml` as follows:
|
can be set in `Rocket.toml` as follows:
|
||||||
|
|
||||||
```toml
|
```
|
||||||
[development]
|
[development]
|
||||||
template_dir = "dev_templates/"
|
template_dir = "dev_templates/"
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ parameter. The value of `tls` must be a table with two keys:
|
||||||
|
|
||||||
The recommended way to specify these parameters is via the `global` environment:
|
The recommended way to specify these parameters is via the `global` environment:
|
||||||
|
|
||||||
```toml
|
```
|
||||||
[global.tls]
|
[global.tls]
|
||||||
certs = "/path/to/certs.pem"
|
certs = "/path/to/certs.pem"
|
||||||
key = "/path/to/key.pem"
|
key = "/path/to/key.pem"
|
||||||
|
@ -187,7 +187,7 @@ key = "/path/to/key.pem"
|
||||||
|
|
||||||
Of course, you can always specify the configuration values per environment:
|
Of course, you can always specify the configuration values per environment:
|
||||||
|
|
||||||
```toml
|
```
|
||||||
[development]
|
[development]
|
||||||
tls = { certs = "/path/to/certs.pem", key = "/path/to/key.pem" }
|
tls = { certs = "/path/to/certs.pem", key = "/path/to/key.pem" }
|
||||||
```
|
```
|
||||||
|
@ -196,7 +196,7 @@ In order for TLS support to be enabled, Rocket must be compiled with the `"tls"`
|
||||||
feature. To do this, add the `"tls"` feature to the `rocket` dependency in your
|
feature. To do this, add the `"tls"` feature to the `rocket` dependency in your
|
||||||
`Cargo.toml` file:
|
`Cargo.toml` file:
|
||||||
|
|
||||||
```toml
|
```
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rocket = { version = "0.2.8", features = ["tls"] }
|
rocket = { version = "0.2.8", features = ["tls"] }
|
||||||
```
|
```
|
||||||
|
|
|
@ -28,7 +28,7 @@ Rocket project by running the following command in the directory:
|
||||||
rustup override set nightly
|
rustup override set nightly
|
||||||
```
|
```
|
||||||
|
|
||||||
### Minimum Nightly Version
|
### Minimum Nightly
|
||||||
|
|
||||||
Rocket always requires the _latest_ version of Rust nightly. If your Rocket
|
Rocket always requires the _latest_ version of Rust nightly. If your Rocket
|
||||||
application suddently stops building, ensure you're using the latest version of
|
application suddently stops building, ensure you're using the latest version of
|
||||||
|
@ -86,7 +86,7 @@ run`. You should see the following:
|
||||||
=> address: localhost
|
=> address: localhost
|
||||||
=> port: 8000
|
=> port: 8000
|
||||||
=> log: normal
|
=> log: normal
|
||||||
=> workers: [logical core count * 2]
|
=> workers: [core count * 2]
|
||||||
=> secret key: generated
|
=> secret key: generated
|
||||||
=> limits: forms = 32KiB
|
=> limits: forms = 32KiB
|
||||||
=> tls: disabled
|
=> tls: disabled
|
||||||
|
|
|
@ -40,7 +40,8 @@ lifecycle as the following sequence of steps:
|
||||||
|
|
||||||
The remainder of this section details the _routing_ phase as well as additional
|
The remainder of this section details the _routing_ phase as well as additional
|
||||||
components needed for Rocket to begin dispatching requests to request handlers.
|
components needed for Rocket to begin dispatching requests to request handlers.
|
||||||
The sections following describe the request and response phases.
|
The sections following describe the request and response phases as well as other
|
||||||
|
components of Rocket.
|
||||||
|
|
||||||
## Routing
|
## Routing
|
||||||
|
|
||||||
|
@ -77,12 +78,14 @@ constructing routes.
|
||||||
|
|
||||||
Before Rocket can dispatch requests to a route, the route needs to be _mounted_.
|
Before Rocket can dispatch requests to a route, the route needs to be _mounted_.
|
||||||
Mounting a route is like namespacing it. Routes are mounted via the `mount`
|
Mounting a route is like namespacing it. Routes are mounted via the `mount`
|
||||||
method on a `Rocket` instance which are themselves created with the
|
method on a `Rocket` instance. A `Rocket` instance is typically created with the
|
||||||
`rocket::ignite()` static method.
|
`rocket::ignite()` static method.
|
||||||
|
|
||||||
The `mount` method takes **1)** a path to namespace a list of routes under, and
|
The `mount` method takes:
|
||||||
**2)** a list of route handlers through the `routes!` macro. The `routes!` macro
|
|
||||||
ties Rocket's code generation to your application.
|
1. A path to namespace a list of routes under,
|
||||||
|
2. A list of route handlers through the `routes!` macro, tying Rocket's code
|
||||||
|
generation to your application.
|
||||||
|
|
||||||
For instance, to mount the `world` route we declared above, we can write the
|
For instance, to mount the `world` route we declared above, we can write the
|
||||||
following:
|
following:
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
Before you can start writing a Rocket application, you'll need a **nightly**
|
Before you can start writing a Rocket application, you'll need a **nightly**
|
||||||
version of Rust installed. We recommend you use [rustup](https://rustup.rs/) to
|
version of Rust installed. We recommend you use [rustup](https://rustup.rs/) to
|
||||||
install or configure such a version. If you don't have Rust installed and want
|
install or configure such a version. If you don't have Rust installed and would
|
||||||
extra guidance installing it, the [getting started](/guide/getting-started)
|
like extra guidance doing so, see the [getting started](/guide/getting-started)
|
||||||
section provides a guide.
|
section.
|
||||||
|
|
||||||
## Running Examples
|
## Running Examples
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ Among other things, you can ask Rocket to automatically validate:
|
||||||
|
|
||||||
The route attribute and function signature work in tandem to describe these
|
The route attribute and function signature work in tandem to describe these
|
||||||
validations. Rocket's code generation takes care of actually validating the
|
validations. Rocket's code generation takes care of actually validating the
|
||||||
proprerties. The remainder of this section describes how to ask Rocket to
|
properties. This section describes how to ask Rocket to validate against all of
|
||||||
validate against all of these properties and more.
|
these properties and more.
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
|
@ -38,7 +38,9 @@ to the root path:
|
||||||
```
|
```
|
||||||
|
|
||||||
The grammar for these attributes is defined formally in the
|
The grammar for these attributes is defined formally in the
|
||||||
[rocket_codegen](https://api.rocket.rs/rocket_codegen/) API docs.
|
[`rocket_codegen`](https://api.rocket.rs/rocket_codegen/) API docs.
|
||||||
|
|
||||||
|
### HEAD Requests
|
||||||
|
|
||||||
Rocket handles `HEAD` requests automatically when there exists a `GET` route
|
Rocket handles `HEAD` requests automatically when there exists a `GET` route
|
||||||
that would otherwise match. It does this by stripping the body from the
|
that would otherwise match. It does this by stripping the body from the
|
||||||
|
@ -46,10 +48,10 @@ response, if there is one. You can also specialize the handling of a `HEAD`
|
||||||
request by declaring a route for it; Rocket won't interfere with `HEAD` requests
|
request by declaring a route for it; Rocket won't interfere with `HEAD` requests
|
||||||
your application handles.
|
your application handles.
|
||||||
|
|
||||||
### Reinterpreting Methods
|
### Reinterpreting
|
||||||
|
|
||||||
Because browsers only send `GET` and `POST` requests, Rocket _reinterprets_
|
Because browsers can only send `GET` and `POST` requests, Rocket _reinterprets_
|
||||||
requests under certain conditions. If a `POST` request contains a body of
|
request methods under certain conditions. If a `POST` request contains a body of
|
||||||
`Content-Type: application/x-www-form-urlencoded`, and the form's **first**
|
`Content-Type: application/x-www-form-urlencoded`, and the form's **first**
|
||||||
field has the name `_method` and a valid HTTP method name as its value (such as
|
field has the name `_method` and a valid HTTP method name as its value (such as
|
||||||
`"PUT"`), that field's value is used as the method for the incoming request.
|
`"PUT"`), that field's value is used as the method for the incoming request.
|
||||||
|
@ -60,7 +62,7 @@ makes use of this feature to submit `PUT` and `DELETE` requests from a web form.
|
||||||
## Dynamic Segments
|
## Dynamic Segments
|
||||||
|
|
||||||
You can declare path segments as dynamic by using angle brackets around variable
|
You can declare path segments as dynamic by using angle brackets around variable
|
||||||
names in a route's path. For example, if we wanted to say _Hello!_ to anything,
|
names in a route's path. For example, if we want to say _Hello!_ to anything,
|
||||||
not just the world, we can declare a route like so:
|
not just the world, we can declare a route like so:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -76,11 +78,11 @@ any request to a path with two non-empty segments, where the first segment is
|
||||||
visit `/hello/John`, the application would respond with `Hello, John!`.
|
visit `/hello/John`, the application would respond with `Hello, John!`.
|
||||||
|
|
||||||
Any number of dynamic path segments are allowed. A path segment can be of any
|
Any number of dynamic path segments are allowed. A path segment can be of any
|
||||||
type, including your own, as long as the type implements the [`FromParam`].
|
type, including your own, as long as the type implements the [`FromParam`]
|
||||||
Rocket implements `FromParam` for many of the standard library types, as well as
|
trait. Rocket implements `FromParam` for many of the standard library types, as
|
||||||
a few special Rocket types. For the full list of supplied implementations, see
|
well as a few special Rocket types. For the full list of supplied
|
||||||
the [`FromParam` API docs]. Here's a more complete route to illustrate varied
|
implementations, see the [`FromParam` API docs]. Here's a more complete route to
|
||||||
usage:
|
illustrate varied usage:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[get("/hello/<name>/<age>/<cool>")]
|
#[get("/hello/<name>/<age>/<cool>")]
|
||||||
|
@ -124,11 +126,11 @@ example:
|
||||||
fn hello(name: String, age: u8, cool: bool) -> String { ... }
|
fn hello(name: String, age: u8, cool: bool) -> String { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
What if `cool` isn't a `bool`? Or, what if `age` isn't a `u8`? In this case,
|
What if `cool` isn't a `bool`? Or, what if `age` isn't a `u8`? When a parameter
|
||||||
Rocket _forwards_ the request to the next matching route, if there is any. This
|
type mismatch occurs, Rocket _forwards_ the request to the next matching route,
|
||||||
continues until a route doesn't forward the request or there are no remaining
|
if there is any. This continues until a route doesn't forward the request or
|
||||||
routes to try. When there are no remaining routes, a customizable **404 error**
|
there are no remaining routes to try. When there are no remaining routes, a
|
||||||
is returned.
|
customizable **404 error** is returned.
|
||||||
|
|
||||||
Routes are attempted in increasing _rank_ order. Rocket chooses a default
|
Routes are attempted in increasing _rank_ order. Rocket chooses a default
|
||||||
ranking from -4 to -1, detailed in the next section, for all routes, but a
|
ranking from -4 to -1, detailed in the next section, for all routes, but a
|
||||||
|
@ -167,9 +169,9 @@ would never forward. An `Ok` variant would indicate that `<id>` was a valid
|
||||||
`Err`'s value would contain the string that failed to parse as a `usize`.
|
`Err`'s value would contain the string that failed to parse as a `usize`.
|
||||||
|
|
||||||
By the way, if you were to omit the `rank` parameter in the `user_str` or
|
By the way, if you were to omit the `rank` parameter in the `user_str` or
|
||||||
`user_int` routes, Rocket would emit a warning indicating that the routes
|
`user_int` routes, Rocket would emit an error and abort launch, indicating that
|
||||||
_collide_, or can match against similar incoming requests. The `rank` parameter
|
the routes _collide_, or can match against similar incoming requests. The `rank`
|
||||||
resolves this collision.
|
parameter resolves this collision.
|
||||||
|
|
||||||
### Default Ranking
|
### Default Ranking
|
||||||
|
|
||||||
|
@ -181,14 +183,14 @@ of a route given its properties.
|
||||||
|
|
||||||
| static path | query string | rank | example |
|
| static path | query string | rank | example |
|
||||||
| ------------- | -------------- | ------ | ------------------- |
|
| ------------- | -------------- | ------ | ------------------- |
|
||||||
| yes | yes | -4 | /hello?world=true |
|
| yes | yes | -4 | `/hello?world=true` |
|
||||||
| yes | no | -3 | /hello |
|
| yes | no | -3 | `/hello` |
|
||||||
| no | yes | -2 | /<hi>?world=true |
|
| no | yes | -2 | `/<hi>?world=true` |
|
||||||
| no | no | -1 | /<hi> |
|
| no | no | -1 | `/<hi>` |
|
||||||
|
|
||||||
## Many Dynamic Segments
|
## Multiple Segments
|
||||||
|
|
||||||
You can also match against multiple segments by using `<param..>` in the route
|
You can also match against multiple segments by using `<param..>` in a route
|
||||||
path. The type of such parameters, known as _segments_ parameters, must
|
path. The type of such parameters, known as _segments_ parameters, must
|
||||||
implement [`FromSegments`]. Segments parameters must be the final component of a
|
implement [`FromSegments`]. Segments parameters must be the final component of a
|
||||||
path: any text after a segments parameter will result in a compile-time error.
|
path: any text after a segments parameter will result in a compile-time error.
|
||||||
|
@ -235,8 +237,8 @@ fn new_user(user: JSON<User>) -> T { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
The `format` parameter in the `post` attribute declares that only incoming
|
The `format` parameter in the `post` attribute declares that only incoming
|
||||||
requests with `Content-Type: application/json` will match. (The `data` parameter
|
requests with `Content-Type: application/json` will match `new_user`. (The
|
||||||
is described in the next section.)
|
`data` parameter is described in the next section.)
|
||||||
|
|
||||||
When a route indicates a non-payload-supporting method (`GET`, `HEAD`, and
|
When a route indicates a non-payload-supporting method (`GET`, `HEAD`, and
|
||||||
`OPTIONS`), the `format` route parameter instructs Rocket to check against the
|
`OPTIONS`), the `format` route parameter instructs Rocket to check against the
|
||||||
|
@ -253,7 +255,7 @@ fn user(id: usize) -> JSON<User> { ... }
|
||||||
|
|
||||||
The `format` parameter in the `get` attribute declares that only incoming
|
The `format` parameter in the `get` attribute declares that only incoming
|
||||||
requests with `application/json` as the preferred media type in the `Accept`
|
requests with `application/json` as the preferred media type in the `Accept`
|
||||||
header will match.
|
header will match `user`.
|
||||||
|
|
||||||
## Request Guards
|
## Request Guards
|
||||||
|
|
||||||
|
@ -274,7 +276,7 @@ As an example, the following dummy handler makes use of three request guards,
|
||||||
`A`, `B`, and `C`. An input can be identified as a request guard if it is not
|
`A`, `B`, and `C`. An input can be identified as a request guard if it is not
|
||||||
named in the route attribute. This is why `param` is not a request guard.
|
named in the route attribute. This is why `param` is not a request guard.
|
||||||
|
|
||||||
```rust,ignore
|
```rust
|
||||||
#[get("/<param>")]
|
#[get("/<param>")]
|
||||||
fn index(param: isize, a: A, b: B, c: C) -> ... { ... }
|
fn index(param: isize, a: A, b: B, c: C) -> ... { ... }
|
||||||
```
|
```
|
||||||
|
@ -288,31 +290,6 @@ documentation.
|
||||||
[`FromRequest`]: https://api.rocket.rs/rocket/request/trait.FromRequest.html
|
[`FromRequest`]: https://api.rocket.rs/rocket/request/trait.FromRequest.html
|
||||||
[`Cookies`]: https://api.rocket.rs/rocket/http/enum.Cookies.html
|
[`Cookies`]: https://api.rocket.rs/rocket/http/enum.Cookies.html
|
||||||
|
|
||||||
### Retrieving Metadata
|
|
||||||
|
|
||||||
Sometimes we need data associated with a request that isn't a direct data input.
|
|
||||||
Rocket makes retrieving and validating such information easy through request
|
|
||||||
guards. As an example, consider the built-in [`Cookies`] request guard. Because
|
|
||||||
`Cookies` is a request guard, an argument of its type can simply be added to a
|
|
||||||
handler:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
use rocket::http::Cookies;
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
fn index(cookies: Cookies) -> Option<String> {
|
|
||||||
cookies.get("message")
|
|
||||||
.map(|value| format!("Message: {}", value))
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This results in the incoming request's cookies being accessible from the
|
|
||||||
handler. The [cookies example] on GitHub illustrates further use of the
|
|
||||||
`Cookies` type to get and set cookies, while the [`Cookies`] documentation
|
|
||||||
contains full usage information.
|
|
||||||
|
|
||||||
[cookies example]: https://github.com/SergioBenitez/Rocket/tree/v0.2.8/examples/cookies
|
|
||||||
|
|
||||||
### Custom Guards
|
### Custom Guards
|
||||||
|
|
||||||
You can implement `FromRequest` for your own types. For instance, to protect a
|
You can implement `FromRequest` for your own types. For instance, to protect a
|
||||||
|
@ -325,12 +302,11 @@ then use it as a request guard:
|
||||||
fn sensitive(key: ApiKey) -> &'static str { ... }
|
fn sensitive(key: ApiKey) -> &'static str { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
You might also implement `FromRequest` for an `AdminUser` type that validates
|
You might also implement `FromRequest` for an `AdminUser` type that
|
||||||
that the cookies in the incoming request authenticate an administrator. Then,
|
authenticates an administrator using incoming cookies. Then, any handler with an
|
||||||
any handler with an `AdminUser` or `ApiKey` type in its argument list is assured
|
`AdminUser` or `ApiKey` type in its argument list is assured to only be invoked
|
||||||
to only be invoked if the appropriate conditions are met. Request guards
|
if the appropriate conditions are met. Request guards centralize policies,
|
||||||
centralize policies, resulting in a simpler, safer, and more secure
|
resulting in a simpler, safer, and more secure applications.
|
||||||
applications.
|
|
||||||
|
|
||||||
### Forwarding Guards
|
### Forwarding Guards
|
||||||
|
|
||||||
|
@ -353,7 +329,8 @@ We start with two request guards:
|
||||||
If no user can be authenticated, the guard forwards.
|
If no user can be authenticated, the guard forwards.
|
||||||
|
|
||||||
We now use these two guards in combination with forwarding to implement the
|
We now use these two guards in combination with forwarding to implement the
|
||||||
following three routes to some administrative panel at `/admin`:
|
following three routes, each leading to an administrative control panel at
|
||||||
|
`/admin`:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[get("/admin")]
|
#[get("/admin")]
|
||||||
|
@ -362,7 +339,7 @@ fn admin_panel(admin: AdminUser) -> &'static str {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/admin", rank = 2)]
|
#[get("/admin", rank = 2)]
|
||||||
fn admin_panel_user(admin: User) -> &'static str {
|
fn admin_panel_user(user: User) -> &'static str {
|
||||||
"Sorry, you must be an administrator to access this page."
|
"Sorry, you must be an administrator to access this page."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,18 +353,134 @@ The three routes above encode authentication _and_ authorization. The
|
||||||
`admin_panel` route only succeeds if an administrator is logged in. Only then is
|
`admin_panel` route only succeeds if an administrator is logged in. Only then is
|
||||||
the admin panel displayed. If the user is not an admin, the `AdminUser` route
|
the admin panel displayed. If the user is not an admin, the `AdminUser` route
|
||||||
will forward. Since the `admin_panel_user` route is ranked next highest, it is
|
will forward. Since the `admin_panel_user` route is ranked next highest, it is
|
||||||
tried next. This route succeeds if there is _any_ user signed in, and an
|
attempted next. This route succeeds if there is _any_ user signed in, and an
|
||||||
authorization failure message is displayed. Finally, if a user isn't signed in,
|
authorization failure message is displayed. Finally, if a user isn't signed in,
|
||||||
the `admin_panel_redirect` route is tried. Since this route has no guards, it
|
the `admin_panel_redirect` route is attempted. Since this route has no guards,
|
||||||
always succeeds. The user is redirected to a log in page.
|
it always succeeds. The user is redirected to a log in page.
|
||||||
|
|
||||||
|
## Cookies
|
||||||
|
|
||||||
|
[`Cookies`] is an important, built-in request guard: it allows you to get, set,
|
||||||
|
and remove cookies. Because `Cookies` is a request guard, an argument of its
|
||||||
|
type can simply be added to a handler:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rocket::http::Cookies;
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
fn index(cookies: Cookies) -> Option<String> {
|
||||||
|
cookies.get("message")
|
||||||
|
.map(|value| format!("Message: {}", value))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This results in the incoming request's cookies being accessible from the
|
||||||
|
handler. The example above retrieves a cookie named `message`. Cookies can also
|
||||||
|
be set and removed using the `Cookies` guard. The [cookies example] on GitHub
|
||||||
|
illustrates further use of the `Cookies` type to get and set cookies, while the
|
||||||
|
[`Cookies`] documentation contains complete usage information.
|
||||||
|
|
||||||
|
[cookies example]: https://github.com/SergioBenitez/Rocket/tree/v0.2.8/examples/cookies
|
||||||
|
|
||||||
|
### Private Cookies
|
||||||
|
|
||||||
|
Cookies added via the [`Cookies::add()`] method are set _in the clear._ In other
|
||||||
|
words, the value set is visible by the client. For sensitive data, Rocket
|
||||||
|
provides _private_ cookies.
|
||||||
|
|
||||||
|
Private cookies are just like regular cookies except that they are encrypted
|
||||||
|
using authenticated encryption, a form of encryption which simultaneously
|
||||||
|
provides confidentiality, integrity, and authenticity. This means that private
|
||||||
|
cookies cannot be inspected, tampered with, or manufactured by clients. If you
|
||||||
|
prefer, you can think of private cookies as being signed and encrypted.
|
||||||
|
|
||||||
|
The API for retrieving, adding, and removing private cookies is identical except
|
||||||
|
methods are suffixed with `_private`. These methods are: [`get_private`],
|
||||||
|
[`add_private`], and [`remove_private`]. An example of their usage is below:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
/// Retrieve the user's ID, if any.
|
||||||
|
#[get("/user_id")]
|
||||||
|
fn user_id(cookies: Cookies) -> Option<String> {
|
||||||
|
request.cookies()
|
||||||
|
.get_private("user_id")
|
||||||
|
.map(|cookie| format!("User ID: {}", cookie.value()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the `user_id` cookie.
|
||||||
|
#[post("/logout")]
|
||||||
|
fn logout(mut cookies: Cookies) -> Flash<Redirect> {
|
||||||
|
cookies.remove_private(Cookie::named("user_id"));
|
||||||
|
Flash::success(Redirect::to("/login"), "Successfully logged out.")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[`Cookies::add()`]: https://api.rocket.rs/rocket/http/enum.Cookies.html#method.add
|
||||||
|
|
||||||
|
### Secret Key
|
||||||
|
|
||||||
|
To encrypt private cookies, Rocket uses the 256-bit key specified in the
|
||||||
|
`secret_key` configuration parameter. If one is not specified, Rocket will
|
||||||
|
automatically generate a fresh key. Note, however, that a private cookie can
|
||||||
|
only be decrypted with the same key with which it was encrypted. As such, it is
|
||||||
|
important to set a `secret_key` configuration parameter when using private
|
||||||
|
cookies so that cookies decrypt properly after an application restart. Rocket
|
||||||
|
emits a warning if an application is run in production without a configured
|
||||||
|
`secret_key`.
|
||||||
|
|
||||||
|
Generating a string suitable for use as a `secret_key` configuration value is
|
||||||
|
usually done through tools like `openssl`. Using `openssl`, a 256-bit base64 key
|
||||||
|
can be generated with the command `openssl rand -base64 32`.
|
||||||
|
|
||||||
|
For more information on configuration, see the
|
||||||
|
[Configuration](/guide/configuration) section of the guide.
|
||||||
|
|
||||||
|
[`get_private`]: https://api.rocket.rs/rocket/http/enum.Cookies.html#method.get_private
|
||||||
|
[`add_private`]: https://api.rocket.rs/rocket/http/enum.Cookies.html#method.add_private
|
||||||
|
[`remove_private`]: https://api.rocket.rs/rocket/http/enum.Cookies.html#method.remove_private
|
||||||
|
|
||||||
|
### One-At-A-Time
|
||||||
|
|
||||||
|
For safety reasons, Rocket currently requires that at most one `Cookies`
|
||||||
|
instance be active at a time. It's uncommon to run into this restriction, but it
|
||||||
|
can be confusing to handle if it does crop up.
|
||||||
|
|
||||||
|
If this does happen, Rocket will emit messages to the console that look as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
=> Error: Multiple `Cookies` instances are active at once.
|
||||||
|
=> An instance of `Cookies` must be dropped before another can be retrieved.
|
||||||
|
=> Warning: The retrieved `Cookies` instance will be empty.
|
||||||
|
```
|
||||||
|
|
||||||
|
The messages will be emitted when a violating handler is called. The issue can
|
||||||
|
be resolved by ensuring that two instances of `Cookies` cannot be active at once
|
||||||
|
due to the offending handler. A common error is to have a handler that uses a
|
||||||
|
`Cookies` request guard as well as a `Custom` request guard that retrieves
|
||||||
|
`Cookies`, as so:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[get("/")]
|
||||||
|
fn bad(cookies: Cookies, custom: Custom) { .. }
|
||||||
|
```
|
||||||
|
|
||||||
|
Because the `cookies` guard will fire before the `custom` guard, the `custom`
|
||||||
|
guard will retrieve an instance of `Cookies` when one already exists for
|
||||||
|
`cookies`. This scenario can be fixed by simply swapping the order of the
|
||||||
|
guards:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[get("/")]
|
||||||
|
fn good(custom: Custom, cookies: Cookies) { .. }
|
||||||
|
```
|
||||||
|
|
||||||
## Body Data
|
## Body Data
|
||||||
|
|
||||||
At some point, your web application will need to process body data. Data
|
At some point, your web application will need to process body data. Data
|
||||||
processing, like much of Rocket, is type directed. To indicate that a handler
|
processing, like much of Rocket, is type directed. To indicate that a handler
|
||||||
expects data, annotate it with `data = "<param>"`, where `param` is an argument
|
expects data, annotate it with `data = "<param>"`, where `param` is an argument
|
||||||
in the handler. The argument's type must implement the
|
in the handler. The argument's type must implement the [`FromData`] trait. It
|
||||||
[FromData](https://api.rocket.rs/rocket/data/trait.FromData.html) trait. It
|
|
||||||
looks like this, where `T: FromData`:
|
looks like this, where `T: FromData`:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -395,6 +488,8 @@ looks like this, where `T: FromData`:
|
||||||
fn new(input: T) -> String { ... }
|
fn new(input: T) -> String { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[`FromData`]: https://api.rocket.rs/rocket/data/trait.FromData.html
|
||||||
|
|
||||||
### Forms
|
### Forms
|
||||||
|
|
||||||
Forms are the most common type of data handled in web applications, and Rocket
|
Forms are the most common type of data handled in web applications, and Rocket
|
||||||
|
@ -415,23 +510,23 @@ fn new(task: Form<Task>) -> String { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
The `Form` type implements the `FromData` trait as long as its generic parameter
|
The `Form` type implements the `FromData` trait as long as its generic parameter
|
||||||
implements the
|
implements the [`FromForm`] trait. In the example, we've derived the `FromForm`
|
||||||
[FromForm](https://api.rocket.rs/rocket/request/trait.FromForm.html) trait. In
|
trait automatically for the `Task` structure. `FromForm` can be derived for any
|
||||||
the example, we've derived the `FromForm` trait automatically for the `Task`
|
structure whose fields implement [`FromFormValue`]. If a `POST /todo` request
|
||||||
structure. `FromForm` can be derived for any structure whose fields implement
|
arrives, the form data will automatically be parsed into the `Task` structure.
|
||||||
[FromFormValue](https://api.rocket.rs/rocket/request/trait.FromFormValue.html).
|
If the data that arrives isn't of the correct Content-Type, the request is
|
||||||
If a `POST /todo` request arrives, the form data will automatically be parsed
|
forwarded. If the data doesn't parse or is simply invalid, a customizable `400 -
|
||||||
into the `Task` structure. If the data that arrives isn't of the correct
|
Bad Request` or `422 - Unprocessable Entity` error is returned. As before, a
|
||||||
Content-Type, the request is forwarded. If the data doesn't parse or is simply
|
forward or failure can be caught by using the `Option` and `Result` types:
|
||||||
invalid, a customizable `400 - Bad Request` or `422 - Unprocessable Entity`
|
|
||||||
error is returned. As before, a forward or failure can be caught by using the
|
|
||||||
`Option` and `Result` types:
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[post("/todo", data = "<task>")]
|
#[post("/todo", data = "<task>")]
|
||||||
fn new(task: Option<Form<Task>>) -> String { ... }
|
fn new(task: Option<Form<Task>>) -> String { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[`FromForm`]: https://api.rocket.rs/rocket/request/trait.FromForm.html
|
||||||
|
[`FromFormValue`]: https://api.rocket.rs/rocket/request/trait.FromFormValue.html
|
||||||
|
|
||||||
#### Lenient Parsing
|
#### Lenient Parsing
|
||||||
|
|
||||||
Rocket's `FromForm` parsing is _strict_ by default. In other words, A `Form<T>`
|
Rocket's `FromForm` parsing is _strict_ by default. In other words, A `Form<T>`
|
||||||
|
@ -489,7 +584,7 @@ Rocket will then match the form field named `type` to the structure field named
|
||||||
#### Field Validation
|
#### Field Validation
|
||||||
|
|
||||||
Fields of forms can be easily validated via implementations of the
|
Fields of forms can be easily validated via implementations of the
|
||||||
`FromFormValue` trait. For example, if you'd like to verify that some user is
|
[`FromFormValue`] trait. For example, if you'd like to verify that some user is
|
||||||
over some age in a form, then you might define a new `AdultAge` type, use it as
|
over some age in a form, then you might define a new `AdultAge` type, use it as
|
||||||
a field in a form structure, and implement `FromFormValue` so that it only
|
a field in a form structure, and implement `FromFormValue` so that it only
|
||||||
validates integers over that age:
|
validates integers over that age:
|
||||||
|
@ -554,10 +649,10 @@ The only condition is that the generic type in `JSON` implements the
|
||||||
|
|
||||||
### Streaming
|
### Streaming
|
||||||
|
|
||||||
Sometimes you just want to handle the incoming data directly. For example, you
|
Sometimes you just want to handle incoming data directly. For example, you might
|
||||||
might want to stream the incoming data out to a file. Rocket makes this as
|
want to stream the incoming data out to a file. Rocket makes this as simple as
|
||||||
simple as possible via the
|
possible via the [`Data`](https://api.rocket.rs/rocket/data/struct.Data.html)
|
||||||
[Data](https://api.rocket.rs/rocket/data/struct.Data.html) type:
|
type:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[post("/upload", format = "text/plain", data = "<data>")]
|
#[post("/upload", format = "text/plain", data = "<data>")]
|
||||||
|
@ -567,9 +662,9 @@ fn upload(data: Data) -> io::Result<String> {
|
||||||
```
|
```
|
||||||
|
|
||||||
The route above accepts any `POST` request to the `/upload` path with
|
The route above accepts any `POST` request to the `/upload` path with
|
||||||
`Content-Type` `text/plain` The incoming data is streamed out to
|
`Content-Type: text/plain` The incoming data is streamed out to
|
||||||
`tmp/upload.txt` file, and the number of bytes written is returned as a plain
|
`tmp/upload.txt`, and the number of bytes written is returned as a plain text
|
||||||
text response if the upload succeeds. If the upload fails, an error response is
|
response if the upload succeeds. If the upload fails, an error response is
|
||||||
returned. The handler above is complete. It really is that simple! See the
|
returned. The handler above is complete. It really is that simple! See the
|
||||||
[GitHub example
|
[GitHub example
|
||||||
code](https://github.com/SergioBenitez/Rocket/tree/v0.2.8/examples/raw_upload)
|
code](https://github.com/SergioBenitez/Rocket/tree/v0.2.8/examples/raw_upload)
|
||||||
|
@ -638,7 +733,7 @@ Routing may fail for a variety of reasons. These include:
|
||||||
* A handler returns a [`Responder`](/guide/responses/#responder) that fails.
|
* A handler returns a [`Responder`](/guide/responses/#responder) that fails.
|
||||||
* No matching route was found.
|
* No matching route was found.
|
||||||
|
|
||||||
If any of these conditions occurs, Rocket returns an error to the client. To do
|
If any of these conditions occur, Rocket returns an error to the client. To do
|
||||||
so, Rocket invokes the _error catcher_ corresponding to the error's status code.
|
so, Rocket invokes the _error catcher_ corresponding to the error's status code.
|
||||||
A catcher is like a route, except it only handles errors. Catchers are declared
|
A catcher is like a route, except it only handles errors. Catchers are declared
|
||||||
via the `error` attribute, which takes a single integer corresponding to the
|
via the `error` attribute, which takes a single integer corresponding to the
|
||||||
|
@ -660,10 +755,9 @@ rocket::ignite().catch(errors![not_found])
|
||||||
```
|
```
|
||||||
|
|
||||||
Unlike request handlers, error handlers can only take 0, 1, or 2 parameters of
|
Unlike request handlers, error handlers can only take 0, 1, or 2 parameters of
|
||||||
types [Request](https://api.rocket.rs/rocket/struct.Request.html) and/or
|
types [`Request`](https://api.rocket.rs/rocket/struct.Request.html) and/or
|
||||||
[Error](https://api.rocket.rs/rocket/enum.Error.html). At present, the `Error`
|
[`Error`](https://api.rocket.rs/rocket/enum.Error.html). At present, the `Error`
|
||||||
type is not particularly useful, and so it is often omitted. The
|
type is not particularly useful, and so it is often omitted. The [error catcher
|
||||||
[error catcher
|
|
||||||
example](https://github.com/SergioBenitez/Rocket/tree/v0.2.8/examples/errors) on
|
example](https://github.com/SergioBenitez/Rocket/tree/v0.2.8/examples/errors) on
|
||||||
GitHub illustrates their use in full.
|
GitHub illustrates their use in full.
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,7 @@ use rocket::response::status;
|
||||||
|
|
||||||
#[post("/<id>")]
|
#[post("/<id>")]
|
||||||
fn new(id: usize) -> status::Accepted<String> {
|
fn new(id: usize) -> status::Accepted<String> {
|
||||||
let url = "http://example.com/resource.json";
|
status::Accepted(Some(format!("id: '{}'", id)))
|
||||||
status::Created(url.into(), Some(format!("id: '{}'", id)))
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -90,13 +89,13 @@ fn just_fail() -> Failure {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## `std` Implementations
|
## Implementations
|
||||||
|
|
||||||
Rocket implements `Responder` for many types in Rust's standard library
|
Rocket implements `Responder` for many types in Rust's standard library
|
||||||
including `String`, `&str`, `File`, `Option`, and `Result`. The [`Responder`]
|
including `String`, `&str`, `File`, `Option`, and `Result`. The [`Responder`]
|
||||||
documentation describes these in detail, but we briefly cover a few here.
|
documentation describes these in detail, but we briefly cover a few here.
|
||||||
|
|
||||||
### `&str` and `String`
|
### Strings
|
||||||
|
|
||||||
The `Responder` implementations for `&str` and `String` are straight-forward:
|
The `Responder` implementations for `&str` and `String` are straight-forward:
|
||||||
the string is used as a sized body, and the Content-Type of the response is set
|
the string is used as a sized body, and the Content-Type of the response is set
|
||||||
|
@ -124,7 +123,7 @@ fn handler() -> &'static str {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### `Option<T>` **where** `T: Responder`
|
### `Option`
|
||||||
|
|
||||||
`Option` is _wrapping_ responder: an `Option<T>` can only be returned when `T`
|
`Option` is _wrapping_ responder: an `Option<T>` can only be returned when `T`
|
||||||
implements `Responder`. If the `Option` is `Some`, the wrapped responder is used
|
implements `Responder`. If the `Option` is `Some`, the wrapped responder is used
|
||||||
|
@ -143,7 +142,7 @@ fn files(file: PathBuf) -> Option<NamedFile> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### `Result<T, E>` **where** `E: Debug`, `E: Responder`
|
### `Result`
|
||||||
|
|
||||||
`Result` is a special kind of wrapping responder: its functionality depends on
|
`Result` is a special kind of wrapping responder: its functionality depends on
|
||||||
whether the error type `E` implements `Responder`.
|
whether the error type `E` implements `Responder`.
|
||||||
|
@ -194,8 +193,7 @@ many of these responders in the [`response`] module. Among these are:
|
||||||
|
|
||||||
The `Stream` type deserves special attention. When a large amount of data needs
|
The `Stream` type deserves special attention. When a large amount of data needs
|
||||||
to be sent to the client, it is better to stream the data to the client to avoid
|
to be sent to the client, it is better to stream the data to the client to avoid
|
||||||
consuming large amounts of memory. Rocket provides the
|
consuming large amounts of memory. Rocket provides the [`Stream`] type, making
|
||||||
[Stream](https://api.rocket.rs/rocket/response/struct.Stream.html) type, making
|
|
||||||
this easy. The `Stream` type can be created from any `Read` type. For example,
|
this easy. The `Stream` type can be created from any `Read` type. For example,
|
||||||
to stream from a local Unix stream, we might write:
|
to stream from a local Unix stream, we might write:
|
||||||
|
|
||||||
|
@ -266,9 +264,9 @@ example, if a file ends with `.hbs`, Handlebars is used, while if a file ends
|
||||||
with `.tera`, Tera is used.
|
with `.tera`, Tera is used.
|
||||||
|
|
||||||
For templates to be properly registered, the template fairing must be attached
|
For templates to be properly registered, the template fairing must be attached
|
||||||
to the instance of Rocket. Fairings are explained in the next section. To attach
|
to the instance of Rocket. The [Fairings](/guide/fairings) sections of the guide
|
||||||
the template fairing, simply call `.attach(Template::fairing())` on an instance
|
provides more information on fairings. To attach the template fairing, simply
|
||||||
of `Rocket` as follows:
|
call `.attach(Template::fairing())` on an instance of `Rocket` as follows:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -69,7 +69,7 @@ You can retrieve more than one `State` type in a single route as well:
|
||||||
fn state(hit_count: State<HitCount>, config: State<Config>) -> T { ... }
|
fn state(hit_count: State<HitCount>, config: State<Config>) -> T { ... }
|
||||||
```
|
```
|
||||||
|
|
||||||
### Within a Request Guard
|
### Within Guards
|
||||||
|
|
||||||
It can also be useful to retrieve managed state from a `FromRequest`
|
It can also be useful to retrieve managed state from a `FromRequest`
|
||||||
implementation. To do so, simple invoke `State<T>` as a guard using the
|
implementation. To do so, simple invoke `State<T>` as a guard using the
|
||||||
|
@ -124,7 +124,7 @@ warning: HitCount is not currently being managed by Rocket
|
||||||
--> src/main.rs:2:17
|
--> src/main.rs:2:17
|
||||||
|
|
|
|
||||||
2 | fn count(hit_count: State<HitCount>) -> String {
|
2 | fn count(hit_count: State<HitCount>) -> String {
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: this State request guard will always fail
|
= note: this State request guard will always fail
|
||||||
help: maybe add a call to 'manage' here?
|
help: maybe add a call to 'manage' here?
|
||||||
|
@ -143,9 +143,9 @@ globally, add `#![allow(unmanaged_state)]` to your crate attributes.
|
||||||
You can find a complete example using the `HitCount` structure in the [state
|
You can find a complete example using the `HitCount` structure in the [state
|
||||||
example on
|
example on
|
||||||
GitHub](https://github.com/SergioBenitez/Rocket/tree/v0.2.8/examples/state) and
|
GitHub](https://github.com/SergioBenitez/Rocket/tree/v0.2.8/examples/state) and
|
||||||
learn more about the [manage
|
learn more about the [`manage`
|
||||||
method](https://api.rocket.rs/rocket/struct.Rocket.html#method.manage) and
|
method](https://api.rocket.rs/rocket/struct.Rocket.html#method.manage) and
|
||||||
[State type](https://api.rocket.rs/rocket/struct.State.html) in the API docs.
|
[`State` type](https://api.rocket.rs/rocket/struct.State.html) in the API docs.
|
||||||
|
|
||||||
## Databases
|
## Databases
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ detailed information on how to use Diesel, please see the [Diesel getting
|
||||||
started guide](http://diesel.rs/guides/getting-started/). For this example, we
|
started guide](http://diesel.rs/guides/getting-started/). For this example, we
|
||||||
use the following dependencies:
|
use the following dependencies:
|
||||||
|
|
||||||
```toml
|
```
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rocket = "0.2.8"
|
rocket = "0.2.8"
|
||||||
diesel = { version = "*", features = ["sqlite"] }
|
diesel = { version = "*", features = ["sqlite"] }
|
||||||
|
@ -204,7 +204,7 @@ advocates for using a `DATABASE_URL` environment variable to set the database
|
||||||
URL, and we use the same convention here. Excepting the long-winded types, the
|
URL, and we use the same convention here. Excepting the long-winded types, the
|
||||||
code is fairly straightforward: the `DATABASE_URL` environment variable is
|
code is fairly straightforward: the `DATABASE_URL` environment variable is
|
||||||
stored in the `DATABASE_URL` static, and an `r2d2::Pool` is created using the
|
stored in the `DATABASE_URL` static, and an `r2d2::Pool` is created using the
|
||||||
default configuration parameter and a Diesel `SqliteConnection`
|
default configuration parameters and a Diesel `SqliteConnection`
|
||||||
`ConnectionManager`.
|
`ConnectionManager`.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
@ -235,7 +235,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Connection Request Guard
|
### Connection Guard
|
||||||
|
|
||||||
The second and final step is to implement a request guard that retrieves a
|
The second and final step is to implement a request guard that retrieves a
|
||||||
single connection from the managed connection pool. We create a new type,
|
single connection from the managed connection pool. We create a new type,
|
||||||
|
|
|
@ -30,7 +30,7 @@ instance. Usage is straightforward:
|
||||||
let req = client.get("/");
|
let req = client.get("/");
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Dispatch the request to retrieve the response.
|
4. Dispatch the request to retrieve the response.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let response = req.dispatch();
|
let response = req.dispatch();
|
||||||
|
|
|
@ -141,9 +141,9 @@ color = 'blue'
|
||||||
|
|
||||||
[[bottom_features]]
|
[[bottom_features]]
|
||||||
title = 'Cookies'
|
title = 'Cookies'
|
||||||
text = "Cookies are first-class in Rocket. View, add, or remove cookies without hassle."
|
text = "View, add, or remove cookies, with or without encryption, without hassle."
|
||||||
image = 'cookies-icon'
|
image = 'cookies-icon'
|
||||||
url = '/guide/requests/#request-guards'
|
url = '/guide/requests/#cookies'
|
||||||
button = 'Learn More'
|
button = 'Learn More'
|
||||||
color = 'purple'
|
color = 'purple'
|
||||||
margin = -6
|
margin = -6
|
||||||
|
@ -161,14 +161,14 @@ margin = -29
|
||||||
title = 'Config Environments'
|
title = 'Config Environments'
|
||||||
text = "Configure your application your way for development, staging, and production."
|
text = "Configure your application your way for development, staging, and production."
|
||||||
image = 'config-icon'
|
image = 'config-icon'
|
||||||
url = '/guide/overview/#configuration'
|
url = '/guide/configuration/#environment'
|
||||||
button = 'Learn More'
|
button = 'Learn More'
|
||||||
color = 'yellow'
|
color = 'yellow'
|
||||||
margin = -3
|
margin = -3
|
||||||
|
|
||||||
[[bottom_features]]
|
[[bottom_features]]
|
||||||
title = 'Query Params'
|
title = 'Query Strings'
|
||||||
text = "Handling query parameters isn’t an afterthought in Rocket."
|
text = "Handling query strings and parameters is type-safe and easy in Rocket."
|
||||||
image = 'query-icon'
|
image = 'query-icon'
|
||||||
url = '/guide/requests/#query-strings'
|
url = '/guide/requests/#query-strings'
|
||||||
button = 'Learn More'
|
button = 'Learn More'
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
[[articles]]
|
[[articles]]
|
||||||
title = "Rocket v0.2: Managed State & More"
|
title = "Rocket v0.2: Managed State & More"
|
||||||
|
author = "Sergio Benitez"
|
||||||
|
author_url = "https://sergio.bz"
|
||||||
date = "February 06, 2017"
|
date = "February 06, 2017"
|
||||||
snippet = """
|
snippet = """
|
||||||
Today marks the first major release since Rocket's debut a little over a month
|
Today marks the first major release since Rocket's debut a little over a month
|
||||||
|
@ -7,7 +9,7 @@ ago. Rocket v0.2 packs a ton of new features, fixes, and general improvements.
|
||||||
Much of the development in v0.2 was led by the community, either through reports
|
Much of the development in v0.2 was led by the community, either through reports
|
||||||
via the [GitHub issue tracker](https://github.com/SergioBenitez/Rocket/issues)
|
via the [GitHub issue tracker](https://github.com/SergioBenitez/Rocket/issues)
|
||||||
or via direct contributions. In fact, there have been **20 unique contributors**
|
or via direct contributions. In fact, there have been **20 unique contributors**
|
||||||
to Rocket's code since Rocket's initial introduction! Community feedback has
|
to Rocket's codebase since Rocket's initial introduction! Community feedback has
|
||||||
been incredible. As a special thank you, we include the names of these
|
been incredible. As a special thank you, we include the names of these
|
||||||
contributors at the end of this article.
|
contributors at the end of this article.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
# Rocket v0.2: Managed State & More
|
# Rocket v0.2: Managed State & More
|
||||||
|
|
||||||
**Posted by [Sergio Benitez](https://sergio.bz) on February 06, 2017**
|
<p class="metadata"><strong>
|
||||||
|
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on February 06, 2017
|
||||||
|
</strong></p>
|
||||||
|
|
||||||
|
<!-- we should be able to generate the title and subheading -->
|
||||||
|
|
||||||
Today marks the first major release since Rocket's debut a little over a month
|
Today marks the first major release since Rocket's debut a little over a month
|
||||||
ago. Rocket v0.2 packs a ton of new features, fixes, and general improvements.
|
ago. Rocket v0.2 packs a ton of new features, fixes, and general improvements.
|
||||||
|
|
Loading…
Reference in New Issue