Various guide updates for 0.3.

This commit is contained in:
Sergio Benitez 2017-07-10 04:59:55 -07:00
parent ed14f59c44
commit 1c866f34fa
12 changed files with 253 additions and 151 deletions

View File

@ -3,8 +3,8 @@
Welcome to Rocket!
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
reference for experienced Rocket developers. This guide is conversational in
writing web applications with Rocket and Rust. The guide is also designed to be
a reference for experienced Rocket developers. This guide is conversational in
tone. For concise and purely technical documentation, see the [API
documentation](https://api.rocket.rs).
@ -21,7 +21,8 @@ aspect of Rocket. The sections are:
parsing, and validating.
- **[Responses](responses/):** discusses generating responses.
- **[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
application.
- **[Configuration](configuration/):** how to configure a Rocket application.

View File

@ -63,7 +63,7 @@ value:
[development]
address = "localhost"
port = 8000
workers = [number_of_cpus * 2]
workers = [number of cpus * 2]
log = "normal"
secret_key = [randomly generated at launch]
limits = { forms = 32768 }
@ -71,7 +71,7 @@ limits = { forms = 32768 }
[staging]
address = "0.0.0.0"
port = 80
workers = [number_of_cpus * 2]
workers = [number of cpus * 2]
log = "normal"
secret_key = [randomly generated at launch]
limits = { forms = 32768 }
@ -79,7 +79,7 @@ limits = { forms = 32768 }
[production]
address = "0.0.0.0"
port = 80
workers = [number_of_cpus * 2]
workers = [number of cpus * 2]
log = "critical"
secret_key = [randomly generated at launch]
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
`"1.2.3.4"` in every environment:
```toml
```
[global]
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
can be set in `Rocket.toml` as follows:
```toml
```
[development]
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:
```toml
```
[global.tls]
certs = "/path/to/certs.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:
```toml
```
[development]
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
`Cargo.toml` file:
```toml
```
[dependencies]
rocket = { version = "0.2.8", features = ["tls"] }
```

View File

@ -28,7 +28,7 @@ Rocket project by running the following command in the directory:
rustup override set nightly
```
### Minimum Nightly Version
### Minimum Nightly
Rocket always requires the _latest_ version of Rust nightly. If your Rocket
application suddently stops building, ensure you're using the latest version of
@ -86,7 +86,7 @@ run`. You should see the following:
=> address: localhost
=> port: 8000
=> log: normal
=> workers: [logical core count * 2]
=> workers: [core count * 2]
=> secret key: generated
=> limits: forms = 32KiB
=> tls: disabled

View File

@ -40,7 +40,8 @@ lifecycle as the following sequence of steps:
The remainder of this section details the _routing_ phase as well as additional
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
@ -77,12 +78,14 @@ constructing routes.
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`
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.
The `mount` method takes **1)** a path to namespace a list of routes under, and
**2)** a list of route handlers through the `routes!` macro. The `routes!` macro
ties Rocket's code generation to your application.
The `mount` method takes:
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
following:

View File

@ -2,9 +2,9 @@
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
install or configure such a version. If you don't have Rust installed and want
extra guidance installing it, the [getting started](/guide/getting-started)
section provides a guide.
install or configure such a version. If you don't have Rust installed and would
like extra guidance doing so, see the [getting started](/guide/getting-started)
section.
## Running Examples

View File

@ -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
validations. Rocket's code generation takes care of actually validating the
proprerties. The remainder of this section describes how to ask Rocket to
validate against all of these properties and more.
properties. This section describes how to ask Rocket to validate against all of
these properties and more.
## Methods
@ -38,7 +38,9 @@ to the root path:
```
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
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
your application handles.
### Reinterpreting Methods
### Reinterpreting
Because browsers only send `GET` and `POST` requests, Rocket _reinterprets_
requests under certain conditions. If a `POST` request contains a body of
Because browsers can only send `GET` and `POST` requests, Rocket _reinterprets_
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**
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.
@ -60,7 +62,7 @@ makes use of this feature to submit `PUT` and `DELETE` requests from a web form.
## Dynamic Segments
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:
```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!`.
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`].
Rocket implements `FromParam` for many of the standard library types, as well as
a few special Rocket types. For the full list of supplied implementations, see
the [`FromParam` API docs]. Here's a more complete route to illustrate varied
usage:
type, including your own, as long as the type implements the [`FromParam`]
trait. Rocket implements `FromParam` for many of the standard library types, as
well as a few special Rocket types. For the full list of supplied
implementations, see the [`FromParam` API docs]. Here's a more complete route to
illustrate varied usage:
```rust
#[get("/hello/<name>/<age>/<cool>")]
@ -124,11 +126,11 @@ example:
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,
Rocket _forwards_ the request to the next matching route, if there is any. This
continues until a route doesn't forward the request or there are no remaining
routes to try. When there are no remaining routes, a customizable **404 error**
is returned.
What if `cool` isn't a `bool`? Or, what if `age` isn't a `u8`? When a parameter
type mismatch occurs, Rocket _forwards_ the request to the next matching route,
if there is any. This continues until a route doesn't forward the request or
there are no remaining routes to try. When there are no remaining routes, a
customizable **404 error** is returned.
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
@ -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`.
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
_collide_, or can match against similar incoming requests. The `rank` parameter
resolves this collision.
`user_int` routes, Rocket would emit an error and abort launch, indicating that
the routes _collide_, or can match against similar incoming requests. The `rank`
parameter resolves this collision.
### Default Ranking
@ -181,14 +183,14 @@ of a route given its properties.
| static path | query string | rank | example |
| ------------- | -------------- | ------ | ------------------- |
| yes | yes | -4 | /hello?world=true |
| yes | no | -3 | /hello |
| no | yes | -2 | /&lt;hi>?world=true |
| no | no | -1 | /&lt;hi> |
| yes | yes | -4 | `/hello?world=true` |
| yes | no | -3 | `/hello` |
| no | yes | -2 | `/<hi>?world=true` |
| 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
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.
@ -235,8 +237,8 @@ fn new_user(user: JSON<User>) -> T { ... }
```
The `format` parameter in the `post` attribute declares that only incoming
requests with `Content-Type: application/json` will match. (The `data` parameter
is described in the next section.)
requests with `Content-Type: application/json` will match `new_user`. (The
`data` parameter is described in the next section.)
When a route indicates a non-payload-supporting method (`GET`, `HEAD`, and
`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
requests with `application/json` as the preferred media type in the `Accept`
header will match.
header will match `user`.
## 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
named in the route attribute. This is why `param` is not a request guard.
```rust,ignore
```rust
#[get("/<param>")]
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
[`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
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 { ... }
```
You might also implement `FromRequest` for an `AdminUser` type that validates
that the cookies in the incoming request authenticate an administrator. Then,
any handler with an `AdminUser` or `ApiKey` type in its argument list is assured
to only be invoked if the appropriate conditions are met. Request guards
centralize policies, resulting in a simpler, safer, and more secure
applications.
You might also implement `FromRequest` for an `AdminUser` type that
authenticates an administrator using incoming cookies. Then, any handler with an
`AdminUser` or `ApiKey` type in its argument list is assured to only be invoked
if the appropriate conditions are met. Request guards centralize policies,
resulting in a simpler, safer, and more secure applications.
### Forwarding Guards
@ -353,7 +329,8 @@ We start with two request guards:
If no user can be authenticated, the guard forwards.
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
#[get("/admin")]
@ -362,7 +339,7 @@ fn admin_panel(admin: AdminUser) -> &'static str {
}
#[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."
}
@ -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
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
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,
the `admin_panel_redirect` route is tried. Since this route has no guards, it
always succeeds. The user is redirected to a log in page.
the `admin_panel_redirect` route is attempted. Since this route has no guards,
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
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
expects data, annotate it with `data = "<param>"`, where `param` is an argument
in the handler. The argument's type must implement the
[FromData](https://api.rocket.rs/rocket/data/trait.FromData.html) trait. It
in the handler. The argument's type must implement the [`FromData`] trait. It
looks like this, where `T: FromData`:
```rust
@ -395,6 +488,8 @@ looks like this, where `T: FromData`:
fn new(input: T) -> String { ... }
```
[`FromData`]: https://api.rocket.rs/rocket/data/trait.FromData.html
### Forms
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
implements the
[FromForm](https://api.rocket.rs/rocket/request/trait.FromForm.html) trait. In
the example, we've derived the `FromForm` trait automatically for the `Task`
structure. `FromForm` can be derived for any structure whose fields implement
[FromFormValue](https://api.rocket.rs/rocket/request/trait.FromFormValue.html).
If a `POST /todo` request arrives, the form data will automatically be parsed
into the `Task` structure. If the data that arrives isn't of the correct
Content-Type, the request is forwarded. If the data doesn't parse or is simply
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:
implements the [`FromForm`] trait. In the example, we've derived the `FromForm`
trait automatically for the `Task` structure. `FromForm` can be derived for any
structure whose fields implement [`FromFormValue`]. If a `POST /todo` request
arrives, the form data will automatically be parsed into the `Task` structure.
If the data that arrives isn't of the correct Content-Type, the request is
forwarded. If the data doesn't parse or is simply 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
#[post("/todo", data = "<task>")]
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
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
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
a field in a form structure, and implement `FromFormValue` so that it only
validates integers over that age:
@ -554,10 +649,10 @@ The only condition is that the generic type in `JSON` implements the
### Streaming
Sometimes you just want to handle the incoming data directly. For example, you
might want to stream the incoming data out to a file. Rocket makes this as
simple as possible via the
[Data](https://api.rocket.rs/rocket/data/struct.Data.html) type:
Sometimes you just want to handle incoming data directly. For example, you might
want to stream the incoming data out to a file. Rocket makes this as simple as
possible via the [`Data`](https://api.rocket.rs/rocket/data/struct.Data.html)
type:
```rust
#[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
`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
text response if the upload succeeds. If the upload fails, an error response is
`Content-Type: text/plain` The incoming data is streamed out to
`tmp/upload.txt`, and the number of bytes written is returned as a plain text
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
[GitHub example
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.
* 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.
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
@ -660,10 +755,9 @@ rocket::ignite().catch(errors![not_found])
```
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
[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
[error catcher
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`
type is not particularly useful, and so it is often omitted. The [error catcher
example](https://github.com/SergioBenitez/Rocket/tree/v0.2.8/examples/errors) on
GitHub illustrates their use in full.

View File

@ -41,8 +41,7 @@ use rocket::response::status;
#[post("/<id>")]
fn new(id: usize) -> status::Accepted<String> {
let url = "http://example.com/resource.json";
status::Created(url.into(), Some(format!("id: '{}'", id)))
status::Accepted(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
including `String`, `&str`, `File`, `Option`, and `Result`. The [`Responder`]
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 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`
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
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
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
[Stream](https://api.rocket.rs/rocket/response/struct.Stream.html) type, making
consuming large amounts of memory. Rocket provides the [`Stream`] type, making
this easy. The `Stream` type can be created from any `Read` type. For example,
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.
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
the template fairing, simply call `.attach(Template::fairing())` on an instance
of `Rocket` as follows:
to the instance of Rocket. The [Fairings](/guide/fairings) sections of the guide
provides more information on fairings. To attach the template fairing, simply
call `.attach(Template::fairing())` on an instance of `Rocket` as follows:
```rust
fn main() {

View File

@ -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 { ... }
```
### Within a Request Guard
### Within Guards
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
@ -124,7 +124,7 @@ warning: HitCount is not currently being managed by Rocket
--> src/main.rs:2:17
|
2 | fn count(hit_count: State<HitCount>) -> String {
| ^^^^^^^^^
| ^^^^^^^^
|
= note: this State request guard will always fail
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
example on
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
[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
@ -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
use the following dependencies:
```toml
```
[dependencies]
rocket = "0.2.8"
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
code is fairly straightforward: the `DATABASE_URL` environment variable is
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`.
```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
single connection from the managed connection pool. We create a new type,

View File

@ -14,27 +14,27 @@ instance. Usage is straightforward:
1. Construct a `Rocket` instance that represents the application.
```rust
let rocket = rocket::ignite();
```
```rust
let rocket = rocket::ignite();
```
2. Construct a `Client` using the `Rocket` instance.
```rust
let client = Client::new(rocket).expect("valid rocket instance");
```
```rust
let client = Client::new(rocket).expect("valid rocket instance");
```
3. Construct requests using the `Client` instance.
```rust
let req = client.get("/");
```
```rust
let req = client.get("/");
```
3. Dispatch the request to retrieve the response.
4. Dispatch the request to retrieve the response.
```rust
let response = req.dispatch();
```
```rust
let response = req.dispatch();
```
[`local`]: https://api.rocket.rs/rocket/local/index.html
[`Client`]: https://api.rocket.rs/rocket/local/struct.Client.html

View File

@ -141,9 +141,9 @@ color = 'blue'
[[bottom_features]]
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'
url = '/guide/requests/#request-guards'
url = '/guide/requests/#cookies'
button = 'Learn More'
color = 'purple'
margin = -6
@ -161,14 +161,14 @@ margin = -29
title = 'Config Environments'
text = "Configure your application your way for development, staging, and production."
image = 'config-icon'
url = '/guide/overview/#configuration'
url = '/guide/configuration/#environment'
button = 'Learn More'
color = 'yellow'
margin = -3
[[bottom_features]]
title = 'Query Params'
text = "Handling query parameters isnt an afterthought in Rocket."
title = 'Query Strings'
text = "Handling query strings and parameters is type-safe and easy in Rocket."
image = 'query-icon'
url = '/guide/requests/#query-strings'
button = 'Learn More'

View File

@ -1,5 +1,7 @@
[[articles]]
title = "Rocket v0.2: Managed State & More"
author = "Sergio Benitez"
author_url = "https://sergio.bz"
date = "February 06, 2017"
snippet = """
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
via the [GitHub issue tracker](https://github.com/SergioBenitez/Rocket/issues)
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
contributors at the end of this article.
"""

View File

@ -1,6 +1,10 @@
# 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
ago. Rocket v0.2 packs a ton of new features, fixes, and general improvements.