mirror of https://github.com/rwf2/Rocket.git
Reorganize and upgrade markup in site docs.
The guide is now in docs/guide. All other site assets are being migrated to a separate repository. The guide markup has been upgraded to take advantages of improvements in the static site generator used to build the Rocket website.
This commit is contained in:
parent
a866134212
commit
8d3f1d65ac
|
@ -1 +1,7 @@
|
||||||
* text eol=lf
|
* text eol=lf
|
||||||
|
|
||||||
|
# Denote all files that are truly binary and should not be modified.
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.gif binary
|
||||||
|
*.svg binary
|
||||||
|
|
|
@ -10,5 +10,5 @@ members = [
|
||||||
"contrib/sync_db_pools/lib/",
|
"contrib/sync_db_pools/lib/",
|
||||||
"contrib/dyn_templates/",
|
"contrib/dyn_templates/",
|
||||||
"contrib/ws/",
|
"contrib/ws/",
|
||||||
"site/tests",
|
"docs/tests",
|
||||||
]
|
]
|
||||||
|
|
|
@ -159,4 +159,4 @@ Rocket is licensed under either of the following, at your option:
|
||||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
|
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
|
||||||
* MIT License ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
|
* MIT License ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
The Rocket website source is licensed under [separate terms](site#license).
|
The Rocket website docs are licensed under [separate terms](docs/LICENSE).
|
||||||
|
|
|
@ -619,56 +619,3 @@ Program, unless a warranty or assumption of liability accompanies a
|
||||||
copy of the Program in return for a fee.
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
state the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
{one line to give the program's name and a brief idea of what it does.}
|
|
||||||
Copyright (C) {year} {name of author}
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
|
||||||
notice like this when it starts in an interactive mode:
|
|
||||||
|
|
||||||
{project} Copyright (C) {year} {fullname}
|
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
|
||||||
<http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
+++
|
||||||
|
summary = "introduces Rocket and its philosophy"
|
||||||
|
+++
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
Rocket is a web framework for Rust. If you'd like, you can think of Rocket as
|
Rocket is a web framework for Rust. If you'd like, you can think of Rocket as
|
|
@ -0,0 +1,16 @@
|
||||||
|
+++
|
||||||
|
summary = "a migration guide from Rocket v0.5 to v0.6"
|
||||||
|
+++
|
||||||
|
|
||||||
|
# Upgrading
|
||||||
|
|
||||||
|
This a placeholder for an eventual migration guide from v0.5 to v0.6.
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
If you run into any issues upgrading, we encourage you to ask questions via
|
||||||
|
[GitHub discussions] or via chat at [`#rocket:mozilla.org`] on Matrix. The
|
||||||
|
[FAQ](../faq/) also provides answers to commonly asked questions.
|
||||||
|
|
||||||
|
[GitHub discussions]: @github/discussions
|
||||||
|
[`#rocket:mozilla.org`]: @chat
|
|
@ -1,9 +1,13 @@
|
||||||
|
+++
|
||||||
|
summary = "the minimal steps to running your first Rocket application"
|
||||||
|
+++
|
||||||
|
|
||||||
# Quickstart
|
# Quickstart
|
||||||
|
|
||||||
Before you can start writing a Rocket application, you'll need to install the
|
Before you can start writing a Rocket application, you'll need to install the
|
||||||
Rust toolchain. We recommend using [rustup](https://rustup.rs/). If you don't
|
Rust toolchain. We recommend using [rustup](https://rustup.rs/). If you don't
|
||||||
have Rust installed and would like extra guidance doing so, see the [getting
|
have Rust installed and would like extra guidance doing so, see [Getting
|
||||||
started](../getting-started) section.
|
Started].
|
||||||
|
|
||||||
## Running Examples
|
## Running Examples
|
||||||
|
|
||||||
|
@ -28,4 +32,4 @@ with `cargo run`.
|
||||||
libraries. When copying the examples for your own use, you should modify the
|
libraries. When copying the examples for your own use, you should modify the
|
||||||
`Cargo.toml` files as explained in the [Getting Started] guide.
|
`Cargo.toml` files as explained in the [Getting Started] guide.
|
||||||
|
|
||||||
[Getting Started]: ../getting-started
|
[Getting Started]: ../getting-started/
|
|
@ -1,3 +1,7 @@
|
||||||
|
+++
|
||||||
|
summary = "a gentle introduction to running your first Rocket application"
|
||||||
|
+++
|
||||||
|
|
||||||
# Getting Started
|
# Getting Started
|
||||||
|
|
||||||
Let's create and run our first Rocket application. We'll ensure we have a
|
Let's create and run our first Rocket application. We'll ensure we have a
|
||||||
|
@ -19,7 +23,7 @@ the command:
|
||||||
rustup default stable
|
rustup default stable
|
||||||
```
|
```
|
||||||
|
|
||||||
! note: You may prefer to develop using the _nightly_ channel.
|
! note: You may prefer to develop using the `nightly` channel.
|
||||||
|
|
||||||
The nightly Rust toolchain enables certain improved developer experiences,
|
The nightly Rust toolchain enables certain improved developer experiences,
|
||||||
such as better compile-time diagnostics, when developing with Rocket. You may
|
such as better compile-time diagnostics, when developing with Rocket. You may
|
||||||
|
@ -52,12 +56,9 @@ rocket = "0.6.0-dev"
|
||||||
development version of Rocket, you'll need to point `Cargo.toml` to a Rocket
|
development version of Rocket, you'll need to point `Cargo.toml` to a Rocket
|
||||||
git repository. For example, with `######` replaced with a git commit hash:
|
git repository. For example, with `######` replaced with a git commit hash:
|
||||||
|
|
||||||
`
|
```toml
|
||||||
[dependencies]
|
|
||||||
`
|
|
||||||
`
|
|
||||||
rocket = { git = "https://github.com/rwf2/Rocket", rev = "######" }
|
rocket = { git = "https://github.com/rwf2/Rocket", rev = "######" }
|
||||||
`
|
```
|
||||||
|
|
||||||
Modify `src/main.rs` so that it contains the code for the Rocket `Hello, world!`
|
Modify `src/main.rs` so that it contains the code for the Rocket `Hello, world!`
|
||||||
program, reproduced below:
|
program, reproduced below:
|
|
@ -1,3 +1,7 @@
|
||||||
|
+++
|
||||||
|
summary = "an overview of Rocket's core concepts"
|
||||||
|
+++
|
||||||
|
|
||||||
# Overview
|
# Overview
|
||||||
|
|
||||||
Rocket provides primitives to build web servers and applications with Rust:
|
Rocket provides primitives to build web servers and applications with Rust:
|
||||||
|
@ -75,7 +79,7 @@ incoming `GET` requests. Instead of `#[get]`, we could have used `#[post]` or
|
||||||
`#[put]` for other HTTP methods, or `#[catch]` for serving [custom error
|
`#[put]` for other HTTP methods, or `#[catch]` for serving [custom error
|
||||||
pages](../requests/#error-catchers). Additionally, other route parameters may be
|
pages](../requests/#error-catchers). Additionally, other route parameters may be
|
||||||
necessary when building more interesting applications. The
|
necessary when building more interesting applications. The
|
||||||
[Requests](../requests) chapter, which follows this one, has further details on
|
[Requests](../requests/) chapter, which follows this one, has further details on
|
||||||
routing and error handling.
|
routing and error handling.
|
||||||
|
|
||||||
! note: We prefer `#[macro_use]`, but you may prefer explicit imports.
|
! note: We prefer `#[macro_use]`, but you may prefer explicit imports.
|
||||||
|
@ -192,9 +196,9 @@ as we expected.
|
||||||
! note: This and other examples are on GitHub.
|
! note: This and other examples are on GitHub.
|
||||||
|
|
||||||
An expanded version of this example's complete crate, ready to `cargo run`,
|
An expanded version of this example's complete crate, ready to `cargo run`,
|
||||||
can be found on [GitHub](@example/hello). You can find dozens of other
|
can be found on [GitHub](@git/master/examples/hello). You can find dozens of other
|
||||||
complete examples, spanning all of Rocket's features, in the [GitHub examples
|
complete examples, spanning all of Rocket's features, in the [GitHub examples
|
||||||
directory](@example/).
|
directory](@git/master/examples/).
|
||||||
|
|
||||||
The second approach uses the `#[rocket::main]` route attribute.
|
The second approach uses the `#[rocket::main]` route attribute.
|
||||||
`#[rocket::main]` _also_ generates a `main` function that sets up an async
|
`#[rocket::main]` _also_ generates a `main` function that sets up an async
|
||||||
|
@ -223,8 +227,8 @@ async fn main() -> Result<(), rocket::Error> {
|
||||||
is desired, or when the return value of [`launch()`] is to be inspected. The
|
is desired, or when the return value of [`launch()`] is to be inspected. The
|
||||||
[error handling example] for instance, inspects the return value.
|
[error handling example] for instance, inspects the return value.
|
||||||
|
|
||||||
[`launch()`]: @api/rocket/struct.Rocket.html#method.launch
|
[`launch()`]: @api/master/rocket/struct.Rocket.html#method.launch
|
||||||
[error handling example]: @example/error-handling
|
[error handling example]: @git/master/examples/error-handling
|
||||||
|
|
||||||
## Futures and Async
|
## Futures and Async
|
||||||
|
|
||||||
|
@ -251,17 +255,17 @@ You can find async-ready libraries on [crates.io](https://crates.io) with the
|
||||||
`async` tag.
|
`async` tag.
|
||||||
|
|
||||||
[`Future`]: @std/future/trait.Future.html
|
[`Future`]: @std/future/trait.Future.html
|
||||||
[`Data`]: @api/rocket/struct.Data.html
|
[`Data`]: @api/master/rocket/struct.Data.html
|
||||||
[`DataStream`]: @api/rocket/data/struct.DataStream.html
|
[`DataStream`]: @api/master/rocket/data/enum.DataStream.html
|
||||||
[Routes]: ../requests
|
[Routes]: ../requests/
|
||||||
[Error Catchers]: ../requests#error-catchers
|
[Error Catchers]: ../requests/#error-catchers
|
||||||
[`FromData`]: ../requests#body-data
|
[`FromData`]: ../requests/#body-data
|
||||||
[`FromRequest`]: ../requests#request-guards
|
[`FromRequest`]: ../requests/#request-guards
|
||||||
|
|
||||||
! note
|
! note
|
||||||
|
|
||||||
Rocket uses the tokio runtime. The runtime is started for you if you use
|
Rocket uses the tokio runtime. The runtime is started for you if you
|
||||||
`#[launch]` or `#[rocket::main]`, but you can still `launch()` a Rocket
|
use `#[launch]` or `#[rocket::main]`, but you can still `launch()` a Rocket
|
||||||
instance on a custom-built runtime by not using _either_ attribute.
|
instance on a custom-built runtime by not using _either_ attribute.
|
||||||
|
|
||||||
### Async Routes
|
### Async Routes
|
|
@ -1,3 +1,7 @@
|
||||||
|
+++
|
||||||
|
summary = "handling request and body data: control-flow, parsing, validation"
|
||||||
|
+++
|
||||||
|
|
||||||
# Requests
|
# Requests
|
||||||
|
|
||||||
Together, a [`route`] attribute and function signature specify what must be true
|
Together, a [`route`] attribute and function signature specify what must be true
|
||||||
|
@ -29,7 +33,7 @@ validations. Rocket's code generation takes care of actually validating the
|
||||||
properties. This section describes how to ask Rocket to validate against all of
|
properties. This section describes how to ask Rocket to validate against all of
|
||||||
these properties and more.
|
these properties and more.
|
||||||
|
|
||||||
[`route`]: @api/rocket/attr.route.html
|
[`route`]: @api/master/rocket/attr.route.html
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
|
@ -64,7 +68,7 @@ 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
|
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
|
as its value (such as `"PUT"`), that field's value is used as the method for the
|
||||||
incoming request. This allows Rocket applications to submit non-`POST` forms.
|
incoming request. This allows Rocket applications to submit non-`POST` forms.
|
||||||
The [todo example](@example/todo/static/index.html.tera#L47) makes use of this
|
The [todo example](@git/master/examples/todo/static/index.html.tera#L47) makes use of this
|
||||||
feature to submit `PUT` and `DELETE` requests from a web form.
|
feature to submit `PUT` and `DELETE` requests from a web form.
|
||||||
|
|
||||||
## Dynamic Paths
|
## Dynamic Paths
|
||||||
|
@ -109,8 +113,8 @@ fn hello(name: &str, age: u8, cool: bool) -> String {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`FromParam`]: @api/rocket/request/trait.FromParam.html
|
[`FromParam`]: @api/master/rocket/request/trait.FromParam.html
|
||||||
[`FromParam` API docs]: @api/rocket/request/trait.FromParam.html
|
[`FromParam` API docs]: @api/master/rocket/request/trait.FromParam.html
|
||||||
|
|
||||||
### Multiple Segments
|
### Multiple Segments
|
||||||
|
|
||||||
|
@ -156,10 +160,21 @@ async fn files(file: PathBuf) -> Option<NamedFile> {
|
||||||
If you need to serve static files from your Rocket application, consider using
|
If you need to serve static files from your Rocket application, consider using
|
||||||
[`FileServer`], which makes it as simple as:
|
[`FileServer`], which makes it as simple as:
|
||||||
|
|
||||||
`rocket.mount("/public", FileServer::from("static/"))`
|
```rust
|
||||||
|
# #[macro_use] extern crate rocket;
|
||||||
|
|
||||||
[`FileServer`]: @api/rocket/fs/struct.FileServer.html
|
use rocket::fs::FileServer;
|
||||||
[`FromSegments`]: @api/rocket/request/trait.FromSegments.html
|
|
||||||
|
#[launch]
|
||||||
|
fn rocket() -> _ {
|
||||||
|
rocket::build()
|
||||||
|
// serve files from `/www/static` at path `/public`
|
||||||
|
.mount("/public", FileServer::from("/www/static"))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[`FileServer`]: @api/master/rocket/fs/struct.FileServer.html
|
||||||
|
[`FromSegments`]: @api/master/rocket/request/trait.FromSegments.html
|
||||||
|
|
||||||
### Ignored Segments
|
### Ignored Segments
|
||||||
|
|
||||||
|
@ -188,7 +203,7 @@ fn everything() -> &'static str {
|
||||||
}
|
}
|
||||||
|
|
||||||
# // Ensure there are no collisions.
|
# // Ensure there are no collisions.
|
||||||
# rocket_guide_tests::client(routes![foo_bar, everything]);
|
# rocket_docs_tests::client(routes![foo_bar, everything]);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Forwarding
|
## Forwarding
|
||||||
|
@ -317,9 +332,9 @@ fn foo_bar() { }
|
||||||
|
|
||||||
#[get("/<_..>")]
|
#[get("/<_..>")]
|
||||||
fn everything() { }
|
fn everything() { }
|
||||||
|
#
|
||||||
# // Ensure there are no collisions.
|
# // Ensure there are no collisions.
|
||||||
# rocket_guide_tests::client(routes![foo_bar, everything]);
|
# rocket_docs_tests::client(routes![foo_bar, everything]);
|
||||||
```
|
```
|
||||||
|
|
||||||
Default ranking ensures that `foo_bar`, with a "partial" path color, has higher
|
Default ranking ensures that `foo_bar`, with a "partial" path color, has higher
|
||||||
|
@ -363,8 +378,8 @@ short-circuiting; if one guard fails, the remaining are not attempted. To learn
|
||||||
more about request guards and implementing them, see the [`FromRequest`]
|
more about request guards and implementing them, see the [`FromRequest`]
|
||||||
documentation.
|
documentation.
|
||||||
|
|
||||||
[`FromRequest`]: @api/rocket/request/trait.FromRequest.html
|
[`FromRequest`]: @api/master/rocket/request/trait.FromRequest.html
|
||||||
[`CookieJar`]: @api/rocket/http/struct.CookieJar.html
|
[`CookieJar`]: @api/master/rocket/http/struct.CookieJar.html
|
||||||
|
|
||||||
### Custom Guards
|
### Custom Guards
|
||||||
|
|
||||||
|
@ -567,8 +582,8 @@ fn login(cert: Option<Result<mtls::Certificate, mtls::Error>>) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`mtls::Certificate`]: @api/rocket/mtls/struct.Certificate.html
|
[`mtls::Certificate`]: @api/master/rocket/mtls/struct.Certificate.html
|
||||||
[`mtls::Error`]: @api/rocket/mtls/enum.Error.html
|
[`mtls::Error`]: @api/master/rocket/mtls/enum.Error.html
|
||||||
|
|
||||||
## Cookies
|
## Cookies
|
||||||
|
|
||||||
|
@ -593,7 +608,7 @@ be set and removed using the `CookieJar` guard. The [cookies example] on GitHub
|
||||||
illustrates further use of the `CookieJar` type to get and set cookies, while
|
illustrates further use of the `CookieJar` type to get and set cookies, while
|
||||||
the [`CookieJar`] documentation contains complete usage information.
|
the [`CookieJar`] documentation contains complete usage information.
|
||||||
|
|
||||||
[cookies example]: @example/cookies
|
[cookies example]: @git/master/examples/cookies
|
||||||
|
|
||||||
### Private Cookies
|
### Private Cookies
|
||||||
|
|
||||||
|
@ -641,7 +656,7 @@ fn logout(cookies: &CookieJar<'_>) -> Flash<Redirect> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`CookieJar::add()`]: @api/rocket/http/struct.CookieJar.html#method.add
|
[`CookieJar::add()`]: @api/master/rocket/http/struct.CookieJar.html#method.add
|
||||||
|
|
||||||
### Secret Key
|
### Secret Key
|
||||||
|
|
||||||
|
@ -656,12 +671,13 @@ 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
|
usually done through tools like `openssl`. Using `openssl`, a 256-bit base64 key
|
||||||
can be generated with the command `openssl rand -base64 32`.
|
can be generated with the command `openssl rand -base64 32`.
|
||||||
|
|
||||||
For more information on configuration, see the [Configuration](../configuration)
|
For more information on configuration, see the [Configuration] section of the
|
||||||
section of the guide.
|
guide.
|
||||||
|
|
||||||
[`get_private`]: @api/rocket/http/struct.CookieJar.html#method.get_private
|
[`get_private`]: @api/master/rocket/http/struct.CookieJar.html#method.get_private
|
||||||
[`add_private`]: @api/rocket/http/struct.CookieJar.html#method.add_private
|
[`add_private`]: @api/master/rocket/http/struct.CookieJar.html#method.add_private
|
||||||
[`remove_private`]: @api/rocket/http/struct.CookieJar.html#method.remove_private
|
[`remove_private`]: @api/master/rocket/http/struct.CookieJar.html#method.remove_private
|
||||||
|
[Configuration]: ../configuration/
|
||||||
|
|
||||||
## Format
|
## Format
|
||||||
|
|
||||||
|
@ -718,7 +734,7 @@ header will match `user`. If instead the route had been declared as `post`,
|
||||||
Rocket would match the `format` against the `Content-Type` header of the
|
Rocket would match the `format` against the `Content-Type` header of the
|
||||||
incoming response.
|
incoming response.
|
||||||
|
|
||||||
[`ContentType::parse_flexible()`]: @api/rocket/http/struct.ContentType.html#method.parse_flexible
|
[`ContentType::parse_flexible()`]: @api/master/rocket/http/struct.ContentType.html#method.parse_flexible
|
||||||
|
|
||||||
## Body Data
|
## Body Data
|
||||||
|
|
||||||
|
@ -738,11 +754,11 @@ fn new(input: T) { /* .. */ }
|
||||||
|
|
||||||
Any type that implements [`FromData`] is also known as _a data guard_.
|
Any type that implements [`FromData`] is also known as _a data guard_.
|
||||||
|
|
||||||
[`FromData`]: @api/rocket/data/trait.FromData.html
|
[`FromData`]: @api/master/rocket/data/trait.FromData.html
|
||||||
|
|
||||||
### JSON
|
### JSON
|
||||||
|
|
||||||
The [`Json<T>`](@api/rocket/serde/json/struct.Json.html) guard deserializes body
|
The [`Json<T>`](@api/master/rocket/serde/json/struct.Json.html) guard deserializes body
|
||||||
data as JSON. The only condition is that the generic type `T` implements the
|
data as JSON. The only condition is that the generic type `T` implements the
|
||||||
`Deserialize` trait from [`serde`](https://serde.rs).
|
`Deserialize` trait from [`serde`](https://serde.rs).
|
||||||
|
|
||||||
|
@ -771,26 +787,26 @@ fn new(task: Json<Task<'_>>) { /* .. */ }
|
||||||
you'd like to avoid this extra annotation, you must depend on `serde` directly
|
you'd like to avoid this extra annotation, you must depend on `serde` directly
|
||||||
via your crate's `Cargo.toml`:
|
via your crate's `Cargo.toml`:
|
||||||
|
|
||||||
`
|
```toml
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
`
|
```
|
||||||
|
|
||||||
We always use the extra annotation in the guide, but you may prefer the
|
We always use the extra annotation in the guide, but you may prefer the
|
||||||
alternative.
|
alternative.
|
||||||
|
|
||||||
See the [JSON example](@example/serialization/src/json.rs) on GitHub for a
|
See the [JSON example](@git/master/examples/serialization/src/json.rs) on GitHub for a
|
||||||
complete example.
|
complete example.
|
||||||
|
|
||||||
! note: JSON support requires enabling Rocket's `json` feature flag.
|
! note: JSON support requires enabling Rocket's `json` feature flag.
|
||||||
|
|
||||||
Rocket intentionally places JSON support, as well support for other data
|
Rocket intentionally places JSON support, as well support for other data
|
||||||
formats and features, behind feature flags. See [the api
|
formats and features, behind feature flags. See [the api
|
||||||
docs](@api/rocket/#features) for a list of available features. The `json`
|
docs](@api/master/rocket/#features) for a list of available features. The `json`
|
||||||
feature can be enabled in the `Cargo.toml`:
|
feature can be enabled in the `Cargo.toml`:
|
||||||
|
|
||||||
`
|
```toml
|
||||||
rocket = { version = "0.6.0-dev", features = ["json"] }
|
rocket = { version = "0.6.0-dev", features = ["json"] }
|
||||||
`
|
```
|
||||||
|
|
||||||
### Temporary Files
|
### Temporary Files
|
||||||
|
|
||||||
|
@ -809,13 +825,13 @@ async fn upload(mut file: TempFile<'_>) -> std::io::Result<()> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`TempFile`]: @api/rocket/fs/enum.TempFile.html
|
[`TempFile`]: @api/master/rocket/fs/enum.TempFile.html
|
||||||
|
|
||||||
### Streaming
|
### Streaming
|
||||||
|
|
||||||
Sometimes you just want to handle incoming data directly. For example, you might
|
Sometimes you just want to handle incoming data directly. For example, you might
|
||||||
want to stream the incoming data to some sink. Rocket makes this as simple as
|
want to stream the incoming data to some sink. Rocket makes this as simple as
|
||||||
possible via the [`Data`](@api/rocket/data/struct.Data.html) type:
|
possible via the [`Data`](@api/master/rocket/data/struct.Data.html) type:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #[macro_use] extern crate rocket;
|
# #[macro_use] extern crate rocket;
|
||||||
|
@ -842,9 +858,9 @@ response is returned. The handler above is complete. It really is that simple!
|
||||||
! note: Rocket requires setting limits when reading incoming data.
|
! note: Rocket requires setting limits when reading incoming data.
|
||||||
|
|
||||||
To aid in preventing DoS attacks, Rocket requires you to specify, as a
|
To aid in preventing DoS attacks, Rocket requires you to specify, as a
|
||||||
[`ByteUnit`](@api/rocket/data/struct.ByteUnit.html), the amount of data you're
|
[`ByteUnit`](@api/master/rocket/data/struct.ByteUnit.html), the amount of data you're
|
||||||
willing to accept from the client when `open`ing a data stream. The
|
willing to accept from the client when `open`ing a data stream. The
|
||||||
[`ToByteUnit`](@api/rocket/data/trait.ToByteUnit.html) trait makes specifying
|
[`ToByteUnit`](@api/master/rocket/data/trait.ToByteUnit.html) trait makes specifying
|
||||||
such a value as idiomatic as `128.kibibytes()`.
|
such a value as idiomatic as `128.kibibytes()`.
|
||||||
|
|
||||||
## Forms
|
## Forms
|
||||||
|
@ -915,9 +931,9 @@ struct Upload<'r> {
|
||||||
fn upload_form(upload: Form<Upload<'_>>) { /* .. */ }
|
fn upload_form(upload: Form<Upload<'_>>) { /* .. */ }
|
||||||
```
|
```
|
||||||
|
|
||||||
[`Form`]: @api/rocket/form/struct.Form.html
|
[`Form`]: @api/master/rocket/form/struct.Form.html
|
||||||
[`FromForm`]: @api/rocket/form/trait.FromForm.html
|
[`FromForm`]: @api/master/rocket/form/trait.FromForm.html
|
||||||
[`FromFormField`]: @api/rocket/form/trait.FromFormField.html
|
[`FromFormField`]: @api/master/rocket/form/trait.FromFormField.html
|
||||||
|
|
||||||
### Parsing Strategy
|
### Parsing Strategy
|
||||||
|
|
||||||
|
@ -966,8 +982,8 @@ lenient. `Form` is lenient by default, so a `Form<Lenient<T>>` is redundant, but
|
||||||
`Lenient` can be used to overwrite a strict parse as lenient:
|
`Lenient` can be used to overwrite a strict parse as lenient:
|
||||||
`Option<Lenient<T>>`.
|
`Option<Lenient<T>>`.
|
||||||
|
|
||||||
[`Form<Strict<T>>`]: @api/rocket/form/struct.Strict.html
|
[`Form<Strict<T>>`]: @api/master/rocket/form/struct.Strict.html
|
||||||
[`Lenient`]: @api/rocket/form/struct.Lenient.html
|
[`Lenient`]: @api/master/rocket/form/struct.Lenient.html
|
||||||
|
|
||||||
### Defaults
|
### Defaults
|
||||||
|
|
||||||
|
@ -990,8 +1006,7 @@ struct MyForm<'v> {
|
||||||
ok_or_error: form::Result<'v, Vec<&'v str>>,
|
ok_or_error: form::Result<'v, Vec<&'v str>>,
|
||||||
here_or_false: bool,
|
here_or_false: bool,
|
||||||
}
|
}
|
||||||
|
# rocket_docs_tests::assert_form_parses_ok!(MyForm, "");
|
||||||
# rocket_guide_tests::assert_form_parses_ok!(MyForm, "");
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The default can be overridden or unset using the `#[field(default = expr)]`
|
The default can be overridden or unset using the `#[field(default = expr)]`
|
||||||
|
@ -1020,9 +1035,9 @@ See the [`FromForm` derive] documentation for full details on the `default`
|
||||||
attribute parameter as well documentation on the more expressive `default_with`
|
attribute parameter as well documentation on the more expressive `default_with`
|
||||||
parameter option.
|
parameter option.
|
||||||
|
|
||||||
[`Errors<'_>`]: @api/rocket/form/struct.Errors.html
|
[`Errors<'_>`]: @api/master/rocket/form/struct.Errors.html
|
||||||
[`form::Result`]: @api/rocket/form/type.Result.html
|
[`form::Result`]: @api/master/rocket/form/type.Result.html
|
||||||
[`FromForm` derive]: @api/rocket/derive.FromForm.html
|
[`FromForm` derive]: @api/master/rocket/derive.FromForm.html
|
||||||
|
|
||||||
### Field Renaming
|
### Field Renaming
|
||||||
|
|
||||||
|
@ -1126,10 +1141,10 @@ struct Password<'r> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`form::validate`]: @api/rocket/form/validate/index.html
|
[`form::validate`]: @api/master/rocket/form/validate/index.html
|
||||||
[`form::validate::range`]: @api/rocket/form/validate/fn.range.html
|
[`form::validate::range`]: @api/master/rocket/form/validate/fn.range.html
|
||||||
[`form::Result`]: @api/rocket/form/type.Result.html
|
[`form::Result`]: @api/master/rocket/form/type.Result.html
|
||||||
[`Errors<'_>`]: @api/rocket/form/error/struct.Errors.html
|
[`Errors<'_>`]: @api/master/rocket/form/error/struct.Errors.html
|
||||||
|
|
||||||
In reality, the expression after `validate =` can be _any_ expression as long as
|
In reality, the expression after `validate =` can be _any_ expression as long as
|
||||||
it evaluates to a value of type `Result<(), Errors<'_>>` (aliased by
|
it evaluates to a value of type `Result<(), Errors<'_>>` (aliased by
|
||||||
|
@ -1201,7 +1216,7 @@ use std::str::FromStr;
|
||||||
struct Token<'r>(&'r str);
|
struct Token<'r>(&'r str);
|
||||||
```
|
```
|
||||||
|
|
||||||
[`try_with`]: @api/rocket/form/validate/fn.try_with.html
|
[`try_with`]: @api/master/rocket/form/validate/fn.try_with.html
|
||||||
|
|
||||||
### Collections
|
### Collections
|
||||||
|
|
||||||
|
@ -1267,7 +1282,7 @@ Such a form, URL-encoded, may look like:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# use rocket::form::FromForm;
|
# use rocket::form::FromForm;
|
||||||
# use rocket_guide_tests::{assert_form_parses, assert_not_form_parses};
|
# use rocket_docs_tests::{assert_form_parses, assert_not_form_parses};
|
||||||
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { owner: Person, pet: Pet, }
|
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { owner: Person, pet: Pet, }
|
||||||
# #[derive(FromForm, Debug, PartialEq)] struct Person { name: String }
|
# #[derive(FromForm, Debug, PartialEq)] struct Person { name: String }
|
||||||
# #[derive(FromForm, Debug, PartialEq)] struct Pet { name: String, good_pet: bool, }
|
# #[derive(FromForm, Debug, PartialEq)] struct Pet { name: String, good_pet: bool, }
|
||||||
|
@ -1298,7 +1313,7 @@ place of or in addition to `.`:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# use rocket::form::FromForm;
|
# use rocket::form::FromForm;
|
||||||
# use rocket_guide_tests::{assert_form_parses, assert_not_form_parses};
|
# use rocket_docs_tests::{assert_form_parses, assert_not_form_parses};
|
||||||
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { owner: Person, pet: Pet, }
|
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { owner: Person, pet: Pet, }
|
||||||
# #[derive(FromForm, Debug, PartialEq)] struct Person { name: String }
|
# #[derive(FromForm, Debug, PartialEq)] struct Person { name: String }
|
||||||
# #[derive(FromForm, Debug, PartialEq)] struct Pet { name: String, good_pet: bool, }
|
# #[derive(FromForm, Debug, PartialEq)] struct Pet { name: String, good_pet: bool, }
|
||||||
|
@ -1354,7 +1369,7 @@ Consider the following examples.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# use rocket::form::FromForm;
|
# use rocket::form::FromForm;
|
||||||
# use rocket_guide_tests::{assert_form_parses, assert_not_form_parses};
|
# use rocket_docs_tests::{assert_form_parses, assert_not_form_parses};
|
||||||
# #[derive(FromForm, PartialEq, Debug)] struct MyForm { numbers: Vec<usize>, }
|
# #[derive(FromForm, PartialEq, Debug)] struct MyForm { numbers: Vec<usize>, }
|
||||||
// These form strings...
|
// These form strings...
|
||||||
# assert_form_parses! { MyForm,
|
# assert_form_parses! { MyForm,
|
||||||
|
@ -1423,7 +1438,7 @@ Examples include:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# use rocket::form::FromForm;
|
# use rocket::form::FromForm;
|
||||||
# use rocket_guide_tests::{assert_form_parses, assert_not_form_parses};
|
# use rocket_docs_tests::{assert_form_parses, assert_not_form_parses};
|
||||||
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { name: String, pets: Vec<Pet>, }
|
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { name: String, pets: Vec<Pet>, }
|
||||||
# #[derive(FromForm, Debug, PartialEq)] struct Pet { name: String, good_pet: bool, }
|
# #[derive(FromForm, Debug, PartialEq)] struct Pet { name: String, good_pet: bool, }
|
||||||
// These form strings...
|
// These form strings...
|
||||||
|
@ -1463,7 +1478,7 @@ The rules are exactly the same.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# use rocket::form::FromForm;
|
# use rocket::form::FromForm;
|
||||||
# use rocket_guide_tests::assert_form_parses;
|
# use rocket_docs_tests::assert_form_parses;
|
||||||
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { v: Vec<Vec<usize>>, }
|
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { v: Vec<Vec<usize>>, }
|
||||||
# assert_form_parses! { MyForm,
|
# assert_form_parses! { MyForm,
|
||||||
"v=1&v=2&v=3" => MyForm { v: vec![vec![1], vec![2], vec![3]] },
|
"v=1&v=2&v=3" => MyForm { v: vec![vec![1], vec![2], vec![3]] },
|
||||||
|
@ -1506,7 +1521,7 @@ As an example, the following are equivalent and all parse to `{ "a" => 1, "b" =>
|
||||||
# use std::collections::HashMap;
|
# use std::collections::HashMap;
|
||||||
#
|
#
|
||||||
# use rocket::form::FromForm;
|
# use rocket::form::FromForm;
|
||||||
# use rocket_guide_tests::{map, assert_form_parses};
|
# use rocket_docs_tests::{map, assert_form_parses};
|
||||||
#
|
#
|
||||||
# #[derive(Debug, PartialEq, FromForm)]
|
# #[derive(Debug, PartialEq, FromForm)]
|
||||||
# struct MyForm {
|
# struct MyForm {
|
||||||
|
@ -1561,7 +1576,7 @@ Examples include:
|
||||||
# use std::collections::HashMap;
|
# use std::collections::HashMap;
|
||||||
#
|
#
|
||||||
# use rocket::form::FromForm;
|
# use rocket::form::FromForm;
|
||||||
# use rocket_guide_tests::{map, assert_form_parses};
|
# use rocket_docs_tests::{map, assert_form_parses};
|
||||||
#
|
#
|
||||||
|
|
||||||
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { ids: HashMap<usize, Person>, }
|
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { ids: HashMap<usize, Person>, }
|
||||||
|
@ -1636,7 +1651,7 @@ Examples include:
|
||||||
# use std::collections::HashMap;
|
# use std::collections::HashMap;
|
||||||
#
|
#
|
||||||
# use rocket::form::FromForm;
|
# use rocket::form::FromForm;
|
||||||
# use rocket_guide_tests::{map, assert_form_parses};
|
# use rocket_docs_tests::{map, assert_form_parses};
|
||||||
#
|
#
|
||||||
|
|
||||||
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { m: HashMap<Person, Pet>, }
|
# #[derive(FromForm, Debug, PartialEq)] struct MyForm { m: HashMap<Person, Pet>, }
|
||||||
|
@ -1728,7 +1743,7 @@ Where we have the following symbolic keys:
|
||||||
# use std::collections::HashMap;
|
# use std::collections::HashMap;
|
||||||
#
|
#
|
||||||
# use rocket::form::FromForm;
|
# use rocket::form::FromForm;
|
||||||
# use rocket_guide_tests::{map, bmap, assert_form_parses};
|
# use rocket_docs_tests::{map, bmap, assert_form_parses};
|
||||||
# #[derive(FromForm, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
# #[derive(FromForm, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
# struct Person { name: String, age: usize }
|
# struct Person { name: String, age: usize }
|
||||||
|
|
||||||
|
@ -1806,9 +1821,9 @@ will be returned.
|
||||||
The [forms example], too, makes use of form contexts, as well as every other
|
The [forms example], too, makes use of form contexts, as well as every other
|
||||||
forms feature.
|
forms feature.
|
||||||
|
|
||||||
[`Contextual`]: @api/rocket/form/struct.Contextual.html
|
[`Contextual`]: @api/master/rocket/form/struct.Contextual.html
|
||||||
[`Context`]: @api/rocket/form/struct.Context.html
|
[`Context`]: @api/master/rocket/form/struct.Context.html
|
||||||
[forms example]: @example/forms
|
[forms example]: @git/master/examples/forms
|
||||||
|
|
||||||
## Query Strings
|
## Query Strings
|
||||||
|
|
||||||
|
@ -1851,15 +1866,15 @@ fn cats() -> &'static str {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following GET requests match `cats`. `%E2%99%A5` is encoded `♥`.
|
// The following GET requests match `cats`. `%E2%99%A5` is encoded `♥`.
|
||||||
# let status = rocket_guide_tests::client(routes![cats]).get(
|
# let status = rocket_docs_tests::client(routes![cats]).get(
|
||||||
"/?cat=%E2%99%A5&hello"
|
"/?cat=%E2%99%A5&hello"
|
||||||
# ).dispatch().status();
|
# ).dispatch().status();
|
||||||
# assert_eq!(status, rocket::http::Status::Ok);
|
# assert_eq!(status, rocket::http::Status::Ok);
|
||||||
# let status = rocket_guide_tests::client(routes![cats]).get(
|
# let status = rocket_docs_tests::client(routes![cats]).get(
|
||||||
"/?hello&cat=%E2%99%A5"
|
"/?hello&cat=%E2%99%A5"
|
||||||
# ).dispatch().status();
|
# ).dispatch().status();
|
||||||
# assert_eq!(status, rocket::http::Status::Ok);
|
# assert_eq!(status, rocket::http::Status::Ok);
|
||||||
# let status = rocket_guide_tests::client(routes![cats]).get(
|
# let status = rocket_docs_tests::client(routes![cats]).get(
|
||||||
"/?dogs=amazing&hello&there&cat=%E2%99%A5"
|
"/?dogs=amazing&hello&there&cat=%E2%99%A5"
|
||||||
# ).dispatch().status();
|
# ).dispatch().status();
|
||||||
# assert_eq!(status, rocket::http::Status::Ok);
|
# assert_eq!(status, rocket::http::Status::Ok);
|
||||||
|
@ -1906,7 +1921,7 @@ fn hello(name: &str, color: Vec<Color>, person: Person<'_>, other: Option<usize>
|
||||||
}
|
}
|
||||||
|
|
||||||
// A request with these query segments matches as above.
|
// A request with these query segments matches as above.
|
||||||
# let status = rocket_guide_tests::client(routes![hello]).get("/?\
|
# let status = rocket_docs_tests::client(routes![hello]).get("/?\
|
||||||
name=George&\
|
name=George&\
|
||||||
color=red&\
|
color=red&\
|
||||||
color=green&\
|
color=green&\
|
||||||
|
@ -1948,7 +1963,7 @@ fn user(id: usize, user: User<'_>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// A request with these query segments matches as above.
|
// A request with these query segments matches as above.
|
||||||
# let status = rocket_guide_tests::client(routes![user]).get("/?\
|
# let status = rocket_docs_tests::client(routes![user]).get("/?\
|
||||||
hello&\
|
hello&\
|
||||||
name=Bob+Smith&\
|
name=Bob+Smith&\
|
||||||
id=1337&\
|
id=1337&\
|
||||||
|
@ -2110,13 +2125,13 @@ Rocket provides a built-in default catcher. It produces HTML or JSON, depending
|
||||||
on the value of the `Accept` header. As such, custom catchers only need to be
|
on the value of the `Accept` header. As such, custom catchers only need to be
|
||||||
registered for custom error handling.
|
registered for custom error handling.
|
||||||
|
|
||||||
The [error handling example](@example/error-handling) illustrates catcher use in
|
The [error handling example](@git/master/examples/error-handling) illustrates catcher use in
|
||||||
full, while the [`Catcher`] API documentation provides further details.
|
full, while the [`Catcher`] API documentation provides further details.
|
||||||
|
|
||||||
[`catch`]: @api/rocket/attr.catch.html
|
[`catch`]: @api/master/rocket/attr.catch.html
|
||||||
[`register()`]: @api/rocket/struct.Rocket.html#method.register
|
[`register()`]: @api/master/rocket/struct.Rocket.html#method.register
|
||||||
[`mount()`]: @api/rocket/struct.Rocket.html#method.mount
|
[`mount()`]: @api/master/rocket/struct.Rocket.html#method.mount
|
||||||
[`catchers!`]: @api/rocket/macro.catchers.html
|
[`catchers!`]: @api/master/rocket/macro.catchers.html
|
||||||
[`&Request`]: @api/rocket/struct.Request.html
|
[`&Request`]: @api/master/rocket/struct.Request.html
|
||||||
[`Status`]: @api/rocket/http/struct.Status.html
|
[`Status`]: @api/master/rocket/http/struct.Status.html
|
||||||
[`Catcher`]: @api/rocket/catcher/struct.Catcher.html
|
[`Catcher`]: @api/master/rocket/catcher/struct.Catcher.html
|
|
@ -1,3 +1,7 @@
|
||||||
|
+++
|
||||||
|
summary = "generating responses and using typed URIs"
|
||||||
|
+++
|
||||||
|
|
||||||
# Responses
|
# Responses
|
||||||
|
|
||||||
You may have noticed that the return type of a handler appears to be arbitrary,
|
You may have noticed that the return type of a handler appears to be arbitrary,
|
||||||
|
@ -6,7 +10,7 @@ trait can be returned, including your own. In this section, we describe the
|
||||||
`Responder` trait as well as several useful `Responder`s provided by Rocket.
|
`Responder` trait as well as several useful `Responder`s provided by Rocket.
|
||||||
We'll also briefly discuss how to implement your own `Responder`.
|
We'll also briefly discuss how to implement your own `Responder`.
|
||||||
|
|
||||||
[`Responder`]: @api/rocket/response/trait.Responder.html
|
[`Responder`]: @api/master/rocket/response/trait.Responder.html
|
||||||
|
|
||||||
## Responder
|
## Responder
|
||||||
|
|
||||||
|
@ -17,7 +21,7 @@ decides which to use. For instance, `String` uses a fixed-sized body, while
|
||||||
`File` uses a streamed response. Responders may dynamically adjust their
|
`File` uses a streamed response. Responders may dynamically adjust their
|
||||||
responses according to the incoming `Request` they are responding to.
|
responses according to the incoming `Request` they are responding to.
|
||||||
|
|
||||||
[`Response`]: @api/rocket/response/struct.Response.html
|
[`Response`]: @api/master/rocket/response/struct.Response.html
|
||||||
|
|
||||||
### Wrapping
|
### Wrapping
|
||||||
|
|
||||||
|
@ -31,7 +35,7 @@ struct WrappingResponder<R>(R);
|
||||||
|
|
||||||
A wrapping responder modifies the response returned by `R` before responding
|
A wrapping responder modifies the response returned by `R` before responding
|
||||||
with that same response. For instance, Rocket provides `Responder`s in the
|
with that same response. For instance, Rocket provides `Responder`s in the
|
||||||
[`status` module](@api/rocket/response/status/) that override the status code of
|
[`status` module](@api/master/rocket/response/status/) that override the status code of
|
||||||
the wrapped `Responder`. As an example, the [`Accepted`] type sets the status to
|
the wrapped `Responder`. As an example, the [`Accepted`] type sets the status to
|
||||||
`202 - Accepted`. It can be used as follows:
|
`202 - Accepted`. It can be used as follows:
|
||||||
|
|
||||||
|
@ -47,7 +51,7 @@ fn new(id: usize) -> status::Accepted<String> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Similarly, the types in the [`content` module](@api/rocket/response/content/)
|
Similarly, the types in the [`content` module](@api/master/rocket/response/content/)
|
||||||
can be used to override the Content-Type of a response. For instance, to set the
|
can be used to override the Content-Type of a response. For instance, to set the
|
||||||
Content-Type of `&'static str` to JSON, as well as setting the status code to an
|
Content-Type of `&'static str` to JSON, as well as setting the status code to an
|
||||||
arbitrary one like `418 I'm a teapot`, combine [`content::RawJson`] with
|
arbitrary one like `418 I'm a teapot`, combine [`content::RawJson`] with
|
||||||
|
@ -95,10 +99,10 @@ fn json() -> RawTeapotJson {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`Accepted`]: @api/rocket/response/status/struct.Accepted.html
|
[`Accepted`]: @api/master/rocket/response/status/struct.Accepted.html
|
||||||
[`content::Json`]: @api/rocket/response/content/struct.Json.html
|
[`content::Json`]: @api/master/rocket/response/content/struct.Json.html
|
||||||
[`status::Custom`]: @api/rocket/response/status/struct.Custom.html
|
[`status::Custom`]: @api/master/rocket/response/status/struct.Custom.html
|
||||||
[`serde::json::Json`]: @api/rocket/serde/json/struct.Json.html
|
[`serde::json::Json`]: @api/master/rocket/serde/json/struct.Json.html
|
||||||
[custom responder]: #custom-responders
|
[custom responder]: #custom-responders
|
||||||
|
|
||||||
### Errors
|
### Errors
|
||||||
|
@ -144,7 +148,7 @@ generated by `Status` for these and other codes:
|
||||||
| 100, [200, 205] | Empty with given status. |
|
| 100, [200, 205] | Empty with given status. |
|
||||||
| All others. | Invalid. Errors to `500` catcher. |
|
| All others. | Invalid. Errors to `500` catcher. |
|
||||||
|
|
||||||
[`Status`]: @api/rocket/http/struct.Status.html
|
[`Status`]: @api/master/rocket/http/struct.Status.html
|
||||||
|
|
||||||
## Custom Responders
|
## Custom Responders
|
||||||
|
|
||||||
|
@ -232,8 +236,8 @@ enum Error {
|
||||||
For more on using the `Responder` derive, including details on how to use the
|
For more on using the `Responder` derive, including details on how to use the
|
||||||
derive to define generic responders, see the [`Responder` derive] documentation.
|
derive to define generic responders, see the [`Responder` derive] documentation.
|
||||||
|
|
||||||
[`Responder` derive]: @api/rocket/derive.Responder.html
|
[`Responder` derive]: @api/master/rocket/derive.Responder.html
|
||||||
[`ContentType`]: @api/rocket/http/struct.ContentType.html
|
[`ContentType`]: @api/master/rocket/http/struct.ContentType.html
|
||||||
|
|
||||||
## Implementations
|
## Implementations
|
||||||
|
|
||||||
|
@ -352,14 +356,14 @@ are:
|
||||||
* [`MsgPack`] - Automatically serializes values into MessagePack.
|
* [`MsgPack`] - Automatically serializes values into MessagePack.
|
||||||
* [`Template`] - Renders a dynamic template using handlebars or Tera.
|
* [`Template`] - Renders a dynamic template using handlebars or Tera.
|
||||||
|
|
||||||
[`status`]: @api/rocket/response/status/
|
[`status`]: @api/master/rocket/response/status/
|
||||||
[`content`]: @api/rocket/response/content/
|
[`content`]: @api/master/rocket/response/content/
|
||||||
[`response`]: @api/rocket/response/
|
[`response`]: @api/master/rocket/response/
|
||||||
[`NamedFile`]: @api/rocket/fs/struct.NamedFile.html
|
[`NamedFile`]: @api/master/rocket/fs/struct.NamedFile.html
|
||||||
[`Redirect`]: @api/rocket/response/struct.Redirect.html
|
[`Redirect`]: @api/master/rocket/response/struct.Redirect.html
|
||||||
[`Flash`]: @api/rocket/response/struct.Flash.html
|
[`Flash`]: @api/master/rocket/response/struct.Flash.html
|
||||||
[`MsgPack`]: @api/rocket/serde/msgpack/struct.MsgPack.html
|
[`MsgPack`]: @api/master/rocket/serde/msgpack/struct.MsgPack.html
|
||||||
[`Template`]: @api/rocket_dyn_templates/struct.Template.html
|
[`Template`]: @api/master/rocket_dyn_templates/struct.Template.html
|
||||||
|
|
||||||
### Async Streams
|
### Async Streams
|
||||||
|
|
||||||
|
@ -413,13 +417,13 @@ fn hello() -> TextStream![&'static str] {
|
||||||
See the [`stream`] docs for full details on creating streams including notes on
|
See the [`stream`] docs for full details on creating streams including notes on
|
||||||
how to detect and handle graceful shutdown requests.
|
how to detect and handle graceful shutdown requests.
|
||||||
|
|
||||||
[`stream`]: @api/rocket/response/stream/index.html
|
[`stream`]: @api/master/rocket/response/stream/index.html
|
||||||
[`stream!`]: @api/rocket/response/stream/macro.stream.html
|
[`stream!`]: @api/master/rocket/response/stream/macro.stream.html
|
||||||
[async `Stream`]: https://docs.rs/futures/0.3/futures/stream/trait.Stream.html
|
[async `Stream`]: https://docs.rs/futures/0.3/futures/stream/trait.Stream.html
|
||||||
[`ReaderStream`]: @api/rocket/response/stream/struct.ReaderStream.html
|
[`ReaderStream`]: @api/master/rocket/response/stream/struct.ReaderStream.html
|
||||||
[`TextStream`]: @api/rocket/response/stream/struct.TextStream.html
|
[`TextStream`]: @api/master/rocket/response/stream/struct.TextStream.html
|
||||||
[`EventStream`]: @api/rocket/response/stream/struct.EventStream.html
|
[`EventStream`]: @api/master/rocket/response/stream/struct.EventStream.html
|
||||||
[`chat` example]: @example/chat
|
[`chat` example]: @git/master/examples/chat
|
||||||
|
|
||||||
### WebSockets
|
### WebSockets
|
||||||
|
|
||||||
|
@ -456,8 +460,8 @@ fn echo_stream(ws: WebSocket) -> Stream!['static] {
|
||||||
|
|
||||||
For complete usage details, see the [`rocket_ws`] documentation.
|
For complete usage details, see the [`rocket_ws`] documentation.
|
||||||
|
|
||||||
[HTTP connection upgrades]: @api-v0.5/rocket/response/struct.Response.html#upgrading
|
[HTTP connection upgrades]: @api/master/rocket/response/struct.Response.html#upgrading
|
||||||
[`rocket_ws`]: @api-v0.5/rocket_ws
|
[`rocket_ws`]: @api/master/rocket_ws/
|
||||||
|
|
||||||
### JSON
|
### JSON
|
||||||
|
|
||||||
|
@ -492,10 +496,10 @@ fails, a **500 - Internal Server Error** is returned.
|
||||||
|
|
||||||
The [serialization example] provides further illustration.
|
The [serialization example] provides further illustration.
|
||||||
|
|
||||||
[`Json`]: @api/rocket/serde/json/struct.Json.html
|
[`Json`]: @api/master/rocket/serde/json/struct.Json.html
|
||||||
[`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html
|
[`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html
|
||||||
[`serde`]: https://serde.rs
|
[`serde`]: https://serde.rs
|
||||||
[serialization example]: @example/serialization
|
[serialization example]: @git/master/examples/serialization
|
||||||
|
|
||||||
## Templates
|
## Templates
|
||||||
|
|
||||||
|
@ -544,7 +548,7 @@ fn index() -> Template {
|
||||||
|
|
||||||
To render a template, it must first be registered. The `Template` fairing
|
To render a template, it must first be registered. The `Template` fairing
|
||||||
automatically registers all discoverable templates when attached. The
|
automatically registers all discoverable templates when attached. The
|
||||||
[Fairings](../fairings) sections of the guide provides more information on
|
[Fairings](../fairings/) sections of the guide provides more information on
|
||||||
fairings. To attach the template fairing, simply call
|
fairings. To attach the template fairing, simply call
|
||||||
`.attach(Template::fairing())` on an instance of `Rocket` as follows:
|
`.attach(Template::fairing())` on an instance of `Rocket` as follows:
|
||||||
|
|
||||||
|
@ -570,10 +574,10 @@ used.
|
||||||
! note: The name of the template _does not_ include its extension.
|
! note: The name of the template _does not_ include its extension.
|
||||||
|
|
||||||
For a template file named `index.html.tera`, call `render("index")` and use
|
For a template file named `index.html.tera`, call `render("index")` and use
|
||||||
the name `"index"` in templates, i.e, `{% extends "index" %}` or `{% extends
|
the name `"index"` in templates, i.e, `extends "index"` or `extends "base"`
|
||||||
"base" %}` for `base.html.tera`.
|
for `base.html.tera`.
|
||||||
|
|
||||||
[`context!`]: @api/rocket_dyn_templates/macro.context.html
|
[`context!`]: @api/master/rocket_dyn_templates/macro.context.html
|
||||||
|
|
||||||
### Live Reloading
|
### Live Reloading
|
||||||
|
|
||||||
|
@ -585,10 +589,10 @@ reloading is disabled.
|
||||||
|
|
||||||
The [`Template`] API documentation contains more information about templates,
|
The [`Template`] API documentation contains more information about templates,
|
||||||
including how to customize a template engine to add custom helpers and filters.
|
including how to customize a template engine to add custom helpers and filters.
|
||||||
The [templating example](@example/templating) uses both Tera and Handlebars
|
The [templating example](@git/master/examples/templating) uses both Tera and Handlebars
|
||||||
templating to implement the same application.
|
templating to implement the same application.
|
||||||
|
|
||||||
[configurable]: ../configuration
|
[configurable]: ../configuration/
|
||||||
|
|
||||||
## Typed URIs
|
## Typed URIs
|
||||||
|
|
||||||
|
@ -818,15 +822,15 @@ uri!(person(id = 100, details = "a/b/c"));
|
||||||
|
|
||||||
See the [`FromUriParam`] documentation for further details.
|
See the [`FromUriParam`] documentation for further details.
|
||||||
|
|
||||||
[`Origin`]: @api/rocket/http/uri/struct.Origin.html
|
[`Origin`]: @api/master/rocket/http/uri/struct.Origin.html
|
||||||
[`Part`]: @api/rocket/http/uri/fmt/trait.Part.html
|
[`Part`]: @api/master/rocket/http/uri/fmt/trait.Part.html
|
||||||
[`Uri`]: @api/rocket/http/uri/enum.Uri.html
|
[`Uri`]: @api/master/rocket/http/uri/enum.Uri.html
|
||||||
[`Redirect::to()`]: @api/rocket/response/struct.Redirect.html#method.to
|
[`Redirect::to()`]: @api/master/rocket/response/struct.Redirect.html#method.to
|
||||||
[`uri!`]: @api/rocket/macro.uri.html
|
[`uri!`]: @api/master/rocket/macro.uri.html
|
||||||
[`UriDisplay`]: @api/rocket/http/uri/fmt/trait.UriDisplay.html
|
[`UriDisplay`]: @api/master/rocket/http/uri/fmt/trait.UriDisplay.html
|
||||||
[`FromUriParam`]: @api/rocket/http/uri/fmt/trait.FromUriParam.html
|
[`FromUriParam`]: @api/master/rocket/http/uri/fmt/trait.FromUriParam.html
|
||||||
[`Path`]: @api/rocket/http/uri/fmt/enum.Path.html
|
[`Path`]: @api/master/rocket/http/uri/fmt/enum.Path.html
|
||||||
[`Query`]: @api/rocket/http/uri/fmt/enum.Query.html
|
[`Query`]: @api/master/rocket/http/uri/fmt/enum.Query.html
|
||||||
[`Ignorable`]: @api/rocket/http/uri/fmt/trait.Ignorable.html
|
[`Ignorable`]: @api/master/rocket/http/uri/fmt/trait.Ignorable.html
|
||||||
[`UriDisplayPath`]: @api/rocket/derive.UriDisplayPath.html
|
[`UriDisplayPath`]: @api/master/rocket/derive.UriDisplayPath.html
|
||||||
[`UriDisplayQuery`]: @api/rocket/derive.UriDisplayQuery.html
|
[`UriDisplayQuery`]: @api/master/rocket/derive.UriDisplayQuery.html
|
|
@ -1,3 +1,7 @@
|
||||||
|
+++
|
||||||
|
summary = "managing application state and connecting to databases"
|
||||||
|
+++
|
||||||
|
|
||||||
# State
|
# State
|
||||||
|
|
||||||
Many web applications have a need to maintain state. This can be as simple as
|
Many web applications have a need to maintain state. This can be as simple as
|
||||||
|
@ -27,10 +31,11 @@ The process for using managed state is simple:
|
||||||
ensuring that the type of values you store in managed state implement `Send` +
|
ensuring that the type of values you store in managed state implement `Send` +
|
||||||
`Sync`.
|
`Sync`.
|
||||||
|
|
||||||
|
|
||||||
### Adding State
|
### Adding State
|
||||||
|
|
||||||
To instruct Rocket to manage state for your application, call the
|
To instruct Rocket to manage state for your application, call the
|
||||||
[`manage`](@api/rocket/struct.Rocket.html#method.manage) method
|
[`manage`](@api/master/rocket/struct.Rocket.html#method.manage) method
|
||||||
on an instance of `Rocket`. For example, to ask Rocket to manage a `HitCount`
|
on an instance of `Rocket`. For example, to ask Rocket to manage a `HitCount`
|
||||||
structure with an internal `AtomicUsize` with an initial value of `0`, we can
|
structure with an internal `AtomicUsize` with an initial value of `0`, we can
|
||||||
write the following:
|
write the following:
|
||||||
|
@ -63,7 +68,7 @@ rocket::build()
|
||||||
### Retrieving State
|
### Retrieving State
|
||||||
|
|
||||||
State that is being managed by Rocket can be retrieved via the
|
State that is being managed by Rocket can be retrieved via the
|
||||||
[`&State`](@api/rocket/struct.State.html) type: a [request
|
[`&State`](@api/master/rocket/struct.State.html) type: a [request
|
||||||
guard](../requests/#request-guards) for managed state. To use the request guard,
|
guard](../requests/#request-guards) for managed state. To use the request guard,
|
||||||
add a `&State<T>` type to any request handler, where `T` is the type of the
|
add a `&State<T>` type to any request handler, where `T` is the type of the
|
||||||
managed state. For example, we can retrieve and respond with the current
|
managed state. For example, we can retrieve and respond with the current
|
||||||
|
@ -104,14 +109,14 @@ fn state(hit_count: &State<HitCount>, config: &State<Config>) { /* .. */ }
|
||||||
If you request a `&State<T>` for a `T` that is not `managed`, Rocket will
|
If you request a `&State<T>` for a `T` that is not `managed`, Rocket will
|
||||||
refuse to start your application. This prevents what would have been an
|
refuse to start your application. This prevents what would have been an
|
||||||
unmanaged state runtime error. Unmanaged state is detected at runtime through
|
unmanaged state runtime error. Unmanaged state is detected at runtime through
|
||||||
[_sentinels_](@api/rocket/trait.Sentinel.html), so there are limitations. If a
|
[_sentinels_](@api/master/rocket/trait.Sentinel.html), so there are limitations. If a
|
||||||
limitation is hit, Rocket still won't call the offending route. Instead,
|
limitation is hit, Rocket still won't call the offending route. Instead,
|
||||||
Rocket will log an error message and return a **500** error to the client.
|
Rocket will log an error message and return a **500** error to the client.
|
||||||
|
|
||||||
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 GitHub](@example/state) and learn more about the [`manage`
|
example on GitHub](@git/master/examples/state) and learn more about the [`manage`
|
||||||
method](@api/rocket/struct.Rocket.html#method.manage) and [`State`
|
method](@api/master/rocket/struct.Rocket.html#method.manage) and [`State`
|
||||||
type](@api/rocket/struct.State.html) in the API docs.
|
type](@api/master/rocket/struct.State.html) in the API docs.
|
||||||
|
|
||||||
### Within Guards
|
### Within Guards
|
||||||
|
|
||||||
|
@ -148,8 +153,8 @@ impl<'r> FromRequest<'r> for Item<'r> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`Request::guard()`]: @api/rocket/struct.Request.html#method.guard
|
[`Request::guard()`]: @api/master/rocket/struct.Request.html#method.guard
|
||||||
[`Rocket::state()`]: @api/rocket/struct.Rocket.html#method.state
|
[`Rocket::state()`]: @api/master/rocket/struct.Rocket.html#method.state
|
||||||
|
|
||||||
## Request-Local State
|
## Request-Local State
|
||||||
|
|
||||||
|
@ -211,8 +216,8 @@ which uses request-local state to cache expensive authentication and
|
||||||
authorization computations, and the [`Fairing`] documentation, which uses
|
authorization computations, and the [`Fairing`] documentation, which uses
|
||||||
request-local state to implement request timing.
|
request-local state to implement request timing.
|
||||||
|
|
||||||
[`FromRequest` request-local state]: @api/rocket/request/trait.FromRequest.html#request-local-state
|
[`FromRequest` request-local state]: @api/master/rocket/request/trait.FromRequest.html#request-local-state
|
||||||
[`Fairing`]: @api/rocket/fairing/trait.Fairing.html#request-local-state
|
[`Fairing`]: @api/master/rocket/fairing/trait.Fairing.html#request-local-state
|
||||||
|
|
||||||
## Databases
|
## Databases
|
||||||
|
|
||||||
|
@ -220,7 +225,7 @@ Rocket includes built-in, ORM-agnostic support for databases via
|
||||||
[`rocket_db_pools`]. The library simplifies accessing one or more databases via
|
[`rocket_db_pools`]. The library simplifies accessing one or more databases via
|
||||||
connection pools: data structures that maintain active database connections for
|
connection pools: data structures that maintain active database connections for
|
||||||
use in the application. Database configuration occurs via Rocket's regular
|
use in the application. Database configuration occurs via Rocket's regular
|
||||||
[configuration](../configuration) mechanisms.
|
[configuration](../configuration/) mechanisms.
|
||||||
|
|
||||||
Connecting your Rocket application to a database using `rocket_db_pools` happens
|
Connecting your Rocket application to a database using `rocket_db_pools` happens
|
||||||
in three simple steps:
|
in three simple steps:
|
||||||
|
@ -277,13 +282,13 @@ in three simple steps:
|
||||||
|
|
||||||
For complete usage details, see [`rocket_db_pools`].
|
For complete usage details, see [`rocket_db_pools`].
|
||||||
|
|
||||||
[`rocket_db_pools`]: @api/rocket_db_pools/index.html
|
[`rocket_db_pools`]: @api/master/rocket_db_pools/index.html
|
||||||
[supported database driver list]: @api/rocket_db_pools/index.html#supported-drivers
|
[supported database driver list]: @api/master/rocket_db_pools/index.html#supported-drivers
|
||||||
[database driver features]: @api/rocket_db_pools/index.html#supported-drivers
|
[database driver features]: @api/master/rocket_db_pools/index.html#supported-drivers
|
||||||
[`Pool`]: @api/rocket_db_pools/index.html#supported-drivers
|
[`Pool`]: @api/master/rocket_db_pools/index.html#supported-drivers
|
||||||
[Configure]: @api/rocket_db_pools/index.html#configuration
|
[Configure]: @api/master/rocket_db_pools/index.html#configuration
|
||||||
[Derive `Database`]: @api/rocket_db_pools/derive.Database.html
|
[Derive `Database`]: @api/master/rocket_db_pools/derive.Database.html
|
||||||
[`Connection<$Type>`]: @api/rocket_db_pools/struct.Connection.html
|
[`Connection<$Type>`]: @api/master/rocket_db_pools/struct.Connection.html
|
||||||
|
|
||||||
### Driver Features
|
### Driver Features
|
||||||
|
|
||||||
|
@ -311,13 +316,13 @@ ORMs like [Diesel] via the [`rocket_sync_db_pools`] library, which you may wish
|
||||||
to explore. Usage is similar, but not identical, to `rocket_db_pools`. See the
|
to explore. Usage is similar, but not identical, to `rocket_db_pools`. See the
|
||||||
crate docs for complete usage details.
|
crate docs for complete usage details.
|
||||||
|
|
||||||
[`rocket_sync_db_pools`]: @api/rocket_sync_db_pools/index.html
|
[`rocket_sync_db_pools`]: @api/master/rocket_sync_db_pools/index.html
|
||||||
[diesel]: https://diesel.rs/
|
[diesel]: https://diesel.rs/
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
For examples of CRUD-like "blog" JSON APIs backed by a SQLite database driven by
|
For examples of CRUD-like "blog" JSON APIs backed by a SQLite database driven by
|
||||||
each of `sqlx`, `diesel`, and `rusqlite`, with migrations run automatically for
|
each of `sqlx`, `diesel`, and `rusqlite`, with migrations run automatically for
|
||||||
the former two drivers, see the [databases example](@example/databases). The
|
the former two drivers, see the [databases example](@git/master/examples/databases). The
|
||||||
`sqlx` example uses `rocket_db_pools` while the `diesel` and `rusqlite` examples
|
`sqlx` example uses `rocket_db_pools` while the `diesel` and `rusqlite` examples
|
||||||
use `rocket_sync_db_pools`.
|
use `rocket_sync_db_pools`.
|
|
@ -1,3 +1,7 @@
|
||||||
|
+++
|
||||||
|
summary = "Rocket's structured middleware"
|
||||||
|
+++
|
||||||
|
|
||||||
# Fairings
|
# Fairings
|
||||||
|
|
||||||
Fairings are Rocket's approach to structured middleware. With fairings, your
|
Fairings are Rocket's approach to structured middleware. With fairings, your
|
||||||
|
@ -36,7 +40,7 @@ that can be used to solve problems in a clean, composable, and robust manner.
|
||||||
fairing to record timing and usage statistics or to enforce global security
|
fairing to record timing and usage statistics or to enforce global security
|
||||||
policies.
|
policies.
|
||||||
|
|
||||||
[`Fairing`]: @api/rocket/fairing/trait.Fairing.html
|
[`Fairing`]: @api/master/rocket/fairing/trait.Fairing.html
|
||||||
[request guard]: ../requests/#request-guards
|
[request guard]: ../requests/#request-guards
|
||||||
[request guards]: ../requests/#request-guards
|
[request guards]: ../requests/#request-guards
|
||||||
[data guards]: ../requests/#body-data
|
[data guards]: ../requests/#body-data
|
||||||
|
@ -66,9 +70,9 @@ attached any number of times. Except for [singleton fairings], all attached
|
||||||
instances are polled at runtime. Fairing callbacks may not be commutative; the
|
instances are polled at runtime. Fairing callbacks may not be commutative; the
|
||||||
order in which fairings are attached may be significant.
|
order in which fairings are attached may be significant.
|
||||||
|
|
||||||
[singleton fairings]: @api/rocket/fairing/trait.Fairing.html#singletons
|
[singleton fairings]: @api/master/rocket/fairing/trait.Fairing.html#singletons
|
||||||
[`attach`]: @api/rocket/struct.Rocket.html#method.attach
|
[`attach`]: @api/master/rocket/struct.Rocket.html#method.attach
|
||||||
[`Rocket`]: @api/rocket/struct.Rocket.html
|
[`Rocket`]: @api/master/rocket/struct.Rocket.html
|
||||||
|
|
||||||
### Callbacks
|
### Callbacks
|
||||||
|
|
||||||
|
@ -114,8 +118,8 @@ events is briefly described below and in details in the [`Fairing`] trait docs:
|
||||||
requests. All registered shutdown fairings are run concurrently; resolution
|
requests. All registered shutdown fairings are run concurrently; resolution
|
||||||
of all fairings is awaited before resuming shutdown.
|
of all fairings is awaited before resuming shutdown.
|
||||||
|
|
||||||
[ignition]: @api/rocket/struct.Rocket.html#method.ignite
|
[ignition]: @api/master/rocket/struct.Rocket.html#method.ignite
|
||||||
[shutdown is triggered]: @api/rocket/config/struct.Shutdown.html#triggers
|
[shutdown is triggered]: @api/master/rocket/config/struct.Shutdown.html#triggers
|
||||||
|
|
||||||
## Implementing
|
## Implementing
|
||||||
|
|
||||||
|
@ -127,13 +131,13 @@ fairing and determine the set of callbacks the fairing is registering for. A
|
||||||
[`on_liftoff`], [`on_request`], [`on_response`], and [`on_shutdown`]. Each
|
[`on_liftoff`], [`on_request`], [`on_response`], and [`on_shutdown`]. Each
|
||||||
callback has a default implementation that does absolutely nothing.
|
callback has a default implementation that does absolutely nothing.
|
||||||
|
|
||||||
[`Info`]: @api/rocket/fairing/struct.Info.html
|
[`Info`]: @api/master/rocket/fairing/struct.Info.html
|
||||||
[`info`]: @api/rocket/fairing/trait.Fairing.html#tymethod.info
|
[`info`]: @api/master/rocket/fairing/trait.Fairing.html#tymethod.info
|
||||||
[`on_ignite`]: @api/rocket/fairing/trait.Fairing.html#method.on_ignite
|
[`on_ignite`]: @api/master/rocket/fairing/trait.Fairing.html#method.on_ignite
|
||||||
[`on_liftoff`]: @api/rocket/fairing/trait.Fairing.html#method.on_liftoff
|
[`on_liftoff`]: @api/master/rocket/fairing/trait.Fairing.html#method.on_liftoff
|
||||||
[`on_request`]: @api/rocket/fairing/trait.Fairing.html#method.on_request
|
[`on_request`]: @api/master/rocket/fairing/trait.Fairing.html#method.on_request
|
||||||
[`on_response`]: @api/rocket/fairing/trait.Fairing.html#method.on_response
|
[`on_response`]: @api/master/rocket/fairing/trait.Fairing.html#method.on_response
|
||||||
[`on_shutdown`]: @api/rocket/fairing/trait.Fairing.html#method.on_shutdown
|
[`on_shutdown`]: @api/master/rocket/fairing/trait.Fairing.html#method.on_shutdown
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
|
@ -210,7 +214,7 @@ impl Fairing for Counter {
|
||||||
```
|
```
|
||||||
|
|
||||||
The complete example can be found in the [`Fairing`
|
The complete example can be found in the [`Fairing`
|
||||||
documentation](@api/rocket/fairing/trait.Fairing.html#example).
|
documentation](@api/master/rocket/fairing/trait.Fairing.html#example).
|
||||||
|
|
||||||
## Ad-Hoc Fairings
|
## Ad-Hoc Fairings
|
||||||
|
|
||||||
|
@ -241,4 +245,4 @@ rocket::build()
|
||||||
})));
|
})));
|
||||||
```
|
```
|
||||||
|
|
||||||
[`AdHoc`]: @api/rocket/fairing/struct.AdHoc.html
|
[`AdHoc`]: @api/master/rocket/fairing/struct.AdHoc.html
|
|
@ -1,3 +1,7 @@
|
||||||
|
+++
|
||||||
|
summary = "unit and integration testing with the built-in testing library"
|
||||||
|
+++
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
|
|
||||||
Every application should be well tested and understandable. Rocket provides the
|
Every application should be well tested and understandable. Rocket provides the
|
||||||
|
@ -49,10 +53,10 @@ instance. Usage is straightforward:
|
||||||
# let _ = response;
|
# let _ = response;
|
||||||
```
|
```
|
||||||
|
|
||||||
[`local`]: @api/rocket/local/
|
[`local`]: @api/master/rocket/local/
|
||||||
[`Client`]: @api/rocket/local/#client
|
[`Client`]: @api/master/rocket/local/#client
|
||||||
[`LocalRequest`]: @api/rocket/local/#localrequest
|
[`LocalRequest`]: @api/master/rocket/local/#localrequest
|
||||||
[`Rocket`]: @api/rocket/struct.Rocket.html
|
[`Rocket`]: @api/master/rocket/struct.Rocket.html
|
||||||
|
|
||||||
## Validating Responses
|
## Validating Responses
|
||||||
|
|
||||||
|
@ -72,14 +76,14 @@ a few below:
|
||||||
* [`into_json`]: deserializes the body data on-the-fly as JSON.
|
* [`into_json`]: deserializes the body data on-the-fly as JSON.
|
||||||
* [`into_msgpack`]: deserializes the body data on-the-fly as MessagePack.
|
* [`into_msgpack`]: deserializes the body data on-the-fly as MessagePack.
|
||||||
|
|
||||||
[`LocalResponse`]: @api/rocket/local/blocking/struct.LocalResponse.html
|
[`LocalResponse`]: @api/master/rocket/local/blocking/struct.LocalResponse.html
|
||||||
[`status`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.status
|
[`status`]: @api/master/rocket/local/blocking/struct.LocalResponse.html#method.status
|
||||||
[`content_type`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.content_type
|
[`content_type`]: @api/master/rocket/local/blocking/struct.LocalResponse.html#method.content_type
|
||||||
[`headers`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.headers
|
[`headers`]: @api/master/rocket/local/blocking/struct.LocalResponse.html#method.headers
|
||||||
[`into_string`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.into_string
|
[`into_string`]: @api/master/rocket/local/blocking/struct.LocalResponse.html#method.into_string
|
||||||
[`into_bytes`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.into_bytes
|
[`into_bytes`]: @api/master/rocket/local/blocking/struct.LocalResponse.html#method.into_bytes
|
||||||
[`into_json`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.into_json
|
[`into_json`]: @api/master/rocket/local/blocking/struct.LocalResponse.html#method.into_json
|
||||||
[`into_msgpack`]: @api/rocket/local/blocking/struct.LocalResponse.html#method.into_msgpack
|
[`into_msgpack`]: @api/master/rocket/local/blocking/struct.LocalResponse.html#method.into_msgpack
|
||||||
|
|
||||||
These methods are typically used in combination with the `assert_eq!` or
|
These methods are typically used in combination with the `assert_eq!` or
|
||||||
`assert!` macros as follows:
|
`assert!` macros as follows:
|
||||||
|
@ -271,7 +275,7 @@ mod test {
|
||||||
```
|
```
|
||||||
|
|
||||||
The tests can be run with `cargo test`. You can find the full source code to
|
The tests can be run with `cargo test`. You can find the full source code to
|
||||||
[this example on GitHub](@example/testing).
|
[this example on GitHub](@git/master/examples/testing).
|
||||||
|
|
||||||
## Asynchronous Testing
|
## Asynchronous Testing
|
||||||
|
|
||||||
|
@ -285,9 +289,9 @@ capable of dispatching multiple requests simultaneously. While synthetic, the
|
||||||
a case. For more information, see the [`rocket::local`] and
|
a case. For more information, see the [`rocket::local`] and
|
||||||
[`rocket::local::asynchronous`] documentation.
|
[`rocket::local::asynchronous`] documentation.
|
||||||
|
|
||||||
[`rocket::local`]: @api/rocket/local/index.html
|
[`rocket::local`]: @api/master/rocket/local/index.html
|
||||||
[`rocket::local::asynchronous`]: @api/rocket/local/asynchronous/index.html
|
[`rocket::local::asynchronous`]: @api/master/rocket/local/asynchronous/index.html
|
||||||
[`async_required` `testing` example]: @example/testing/src/async_required.rs
|
[`async_required` `testing` example]: @git/master/examples/testing/src/async_required.rs
|
||||||
|
|
||||||
## Codegen Debug
|
## Codegen Debug
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
+++
|
||||||
|
summary = "overview and customization of Rocket application configuration"
|
||||||
|
+++
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
Rocket's configuration system is flexible. Based on [Figment](@figment), it
|
Rocket's configuration system is flexible. Based on [Figment](@figment), it
|
||||||
|
@ -40,8 +44,8 @@ values:
|
||||||
<small>* Note: the `workers`, `max_blocking`, and `shutdown.force` configuration
|
<small>* Note: the `workers`, `max_blocking`, and `shutdown.force` configuration
|
||||||
parameters are only read from the [default provider](#default-provider).</small>
|
parameters are only read from the [default provider](#default-provider).</small>
|
||||||
|
|
||||||
[client's real IP]: @api/rocket/request/struct.Request.html#method.real_ip
|
[client's real IP]: @api/master/rocket/request/struct.Request.html#method.real_ip
|
||||||
[client to proxy protocol]: @api/rocket/request/struct.Request.html#method.proxy_proto
|
[client to proxy protocol]: @api/master/rocket/request/struct.Request.html#method.proxy_proto
|
||||||
|
|
||||||
### Profiles
|
### Profiles
|
||||||
|
|
||||||
|
@ -61,20 +65,20 @@ profile supplant any values with the same name in any profile.
|
||||||
|
|
||||||
[`Provider`]: @figment/trait.Provider.html
|
[`Provider`]: @figment/trait.Provider.html
|
||||||
[`Profile`]: @figment/struct.Profile.html
|
[`Profile`]: @figment/struct.Profile.html
|
||||||
[`Config`]: @api/rocket/struct.Config.html
|
[`Config`]: @api/master/rocket/struct.Config.html
|
||||||
[`Config::figment()`]: @api/rocket/struct.Config.html#method.figment
|
[`Config::figment()`]: @api/master/rocket/struct.Config.html#method.figment
|
||||||
[`Toml`]: @figment/providers/struct.Toml.html
|
[`Toml`]: @figment/providers/struct.Toml.html
|
||||||
[`Json`]: @figment/providers/struct.Json.html
|
[`Json`]: @figment/providers/struct.Json.html
|
||||||
[`Figment`]: @figment/struct.Figment.html
|
[`Figment`]: @figment/struct.Figment.html
|
||||||
[`Deserialize`]: @api/rocket/serde/trait.Deserialize.html
|
[`Deserialize`]: @api/master/rocket/serde/trait.Deserialize.html
|
||||||
[`LogLevel`]: @api/rocket/config/enum.LogLevel.html
|
[`LogLevel`]: @api/master/rocket/config/enum.LogLevel.html
|
||||||
[`Limits`]: @api/rocket/data/struct.Limits.html
|
[`Limits`]: @api/master/rocket/data/struct.Limits.html
|
||||||
[`Limits::default()`]: @api/rocket/data/struct.Limits.html#impl-Default
|
[`Limits::default()`]: @api/master/rocket/data/struct.Limits.html#impl-Default-for-Limits
|
||||||
[`SecretKey`]: @api/rocket/config/struct.SecretKey.html
|
[`SecretKey`]: @api/master/rocket/config/struct.SecretKey.html
|
||||||
[`CliColors`]: @api/rocket/config/enum.CliColors.html
|
[`CliColors`]: @api/master/rocket/config/enum.CliColors.html
|
||||||
[`TlsConfig`]: @api/rocket/config/struct.TlsConfig.html
|
[`TlsConfig`]: @api/master/rocket/tls/struct.TlsConfig.html
|
||||||
[`Shutdown`]: @api/rocket/config/struct.Shutdown.html
|
[`Shutdown`]: @api/master/rocket/config/struct.Shutdown.html
|
||||||
[`Shutdown::default()`]: @api/rocket/config/struct.Shutdown.html#fields
|
[`Shutdown::default()`]: @api/master/rocket/config/struct.Shutdown.html#fields
|
||||||
|
|
||||||
## Default Provider
|
## Default Provider
|
||||||
|
|
||||||
|
@ -99,7 +103,7 @@ As a result of `Config::figment()`, without any effort, Rocket can be configured
|
||||||
via a `Rocket.toml` file and/or via environment variables, the latter of which
|
via a `Rocket.toml` file and/or via environment variables, the latter of which
|
||||||
take precedence over the former.
|
take precedence over the former.
|
||||||
|
|
||||||
[`Config::default()`]: @api/rocket/struct.Config.html#method.default
|
[`Config::default()`]: @api/master/rocket/struct.Config.html#method.default
|
||||||
|
|
||||||
### Rocket.toml
|
### Rocket.toml
|
||||||
|
|
||||||
|
@ -231,7 +235,7 @@ bytes Rocket should accept for that type. Rocket can parse both integers
|
||||||
By default, Rocket specifies a `32 KiB` limit for incoming forms. Since Rocket
|
By default, Rocket specifies a `32 KiB` limit for incoming forms. Since Rocket
|
||||||
requires specifying a read limit whenever data is read, external data guards may
|
requires specifying a read limit whenever data is read, external data guards may
|
||||||
also choose to have a configure limit via the `limits` parameter. The
|
also choose to have a configure limit via the `limits` parameter. The
|
||||||
[`Json`](@api/rocket/serde/json/struct.Json.html) type, for instance, uses the
|
[`Json`](@api/master/rocket/serde/json/struct.Json.html) type, for instance, uses the
|
||||||
`limits.json` parameter.
|
`limits.json` parameter.
|
||||||
|
|
||||||
### TLS
|
### TLS
|
||||||
|
@ -267,8 +271,8 @@ The `tls` parameter is expected to be a dictionary that deserializes into a
|
||||||
| `prefer_server_cipher_order` | no | Boolean for whether to [prefer server cipher suites]. |
|
| `prefer_server_cipher_order` | no | Boolean for whether to [prefer server cipher suites]. |
|
||||||
| `mutual` | no | A map with [mutual TLS] configuration. |
|
| `mutual` | no | A map with [mutual TLS] configuration. |
|
||||||
|
|
||||||
[`CipherSuite`]: @api/rocket/config/enum.CipherSuite.html
|
[`CipherSuite`]: @api/master/rocket/tls/enum.CipherSuite.html
|
||||||
[prefer server cipher suites]: @api/rocket/config/struct.TlsConfig.html#method.with_preferred_server_cipher_order
|
[prefer server cipher suites]: @api/master/rocket/tls/struct.TlsConfig.html#method.with_preferred_server_cipher_order
|
||||||
[mutual TLS]: #mutual-tls
|
[mutual TLS]: #mutual-tls
|
||||||
|
|
||||||
When specified via TOML or other serialized formats, each [`CipherSuite`] is
|
When specified via TOML or other serialized formats, each [`CipherSuite`] is
|
||||||
|
@ -331,8 +335,8 @@ The `tls.mutual` parameter is expected to be a dictionary that deserializes into
|
||||||
| `ca_certs` | **_yes_** | Path or bytes to DER-encoded X.509 TLS cert chain. |
|
| `ca_certs` | **_yes_** | Path or bytes to DER-encoded X.509 TLS cert chain. |
|
||||||
| `mandatory` | no | Boolean controlling whether the client _must_ authenticate. |
|
| `mandatory` | no | Boolean controlling whether the client _must_ authenticate. |
|
||||||
|
|
||||||
[`MutualTls`]: @api/rocket/config/struct.MutualTls.html
|
[`MtlsConfig`]: @api/master/rocket/mtls/struct.MtlsConfig.html
|
||||||
[`mtls`]: @api/rocket/mtls/index.html
|
[`mtls`]: @api/master/rocket/mtls/index.html
|
||||||
|
|
||||||
Rocket reports if TLS and/or mTLS are enabled at launch time:
|
Rocket reports if TLS and/or mTLS are enabled at launch time:
|
||||||
|
|
||||||
|
@ -355,13 +359,14 @@ fn auth(cert: Certificate<'_>) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The [TLS example](@example/tls) illustrates a fully configured TLS server with
|
The [TLS example](@git/master/examples/tls) illustrates a fully configured TLS server with
|
||||||
mutual TLS.
|
mutual TLS.
|
||||||
|
|
||||||
! warning: Rocket's built-in TLS supports only TLS 1.2 and 1.3. This may not be
|
! warning: Rocket's built-in TLS supports only TLS 1.2 and 1.3.
|
||||||
suitable for production use.
|
|
||||||
|
|
||||||
[`mtls::Certificate`]: @api/rocket/mtls/struct.Certificate.html
|
This may not be suitable for production use requiring legacy support.
|
||||||
|
|
||||||
|
[`mtls::Certificate`]: @api/master/rocket/mtls/struct.Certificate.html
|
||||||
|
|
||||||
### Proxied TLS
|
### Proxied TLS
|
||||||
|
|
||||||
|
@ -385,10 +390,10 @@ via a TOML file:
|
||||||
proxy_proto_header = "X-Forwarded-Proto"
|
proxy_proto_header = "X-Forwarded-Proto"
|
||||||
```
|
```
|
||||||
|
|
||||||
[`Request::proxy_proto()`]: @api/rocket/request/struct.Request.html#method.proxy_proto
|
[`Request::proxy_proto()`]: @api/master/rocket/request/struct.Request.html#method.proxy_proto
|
||||||
[`ProxyProto`]: @api/rocket/http/enum.ProxyProto.html
|
[`ProxyProto`]: @api/master/rocket/http/enum.ProxyProto.html
|
||||||
[`CookieJar`]: @api/rocket/http/struct.CookieJar.html
|
[`CookieJar`]: @api/master/rocket/http/struct.CookieJar.html
|
||||||
[`Request::context_is_likely_secure()`]: @api/rocket/request/struct.Request.html#method.context_is_likely_secure
|
[`Request::context_is_likely_secure()`]: @api/master/rocket/request/struct.Request.html#method.context_is_likely_secure
|
||||||
|
|
||||||
### Workers
|
### Workers
|
||||||
|
|
||||||
|
@ -412,8 +417,8 @@ required such as when performing file system I/O via [`TempFile`] or wrapping
|
||||||
synchronous work via [`rocket_sync_db_pools`].
|
synchronous work via [`rocket_sync_db_pools`].
|
||||||
|
|
||||||
[`spawn_blocking`]: @tokio/task/fn.spawn_blocking.html
|
[`spawn_blocking`]: @tokio/task/fn.spawn_blocking.html
|
||||||
[`TempFile`]: @api/rocket/fs/enum.TempFile.html
|
[`TempFile`]: @api/master/rocket/fs/enum.TempFile.html
|
||||||
[`rocket_sync_db_pools`]: @api/rocket_sync_db_pools/index.html
|
[`rocket_sync_db_pools`]: @api/master/rocket_sync_db_pools/index.html
|
||||||
|
|
||||||
## Extracting Values
|
## Extracting Values
|
||||||
|
|
||||||
|
@ -481,7 +486,7 @@ fn rocket() -> _ {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`Rocket::figment()`]: @api/rocket/struct.Rocket.html#method.figment
|
[`Rocket::figment()`]: @api/master/rocket/struct.Rocket.html#method.figment
|
||||||
|
|
||||||
## Custom Providers
|
## Custom Providers
|
||||||
|
|
||||||
|
@ -567,5 +572,5 @@ that if values like `port` and `address` are configured in `Config`, `App.toml`
|
||||||
or `APP_` environment variables, Rocket will make use of them. The application
|
or `APP_` environment variables, Rocket will make use of them. The application
|
||||||
can also extract its configuration, done here via the `Adhoc::config()` fairing.
|
can also extract its configuration, done here via the `Adhoc::config()` fairing.
|
||||||
|
|
||||||
[`rocket::custom()`]: @api/rocket/fn.custom.html
|
[`rocket::custom()`]: @api/master/rocket/fn.custom.html
|
||||||
[`rocket::build()`]: @api/rocket/fn.custom.html
|
[`rocket::build()`]: @api/master/rocket/fn.custom.html
|
|
@ -1,3 +1,7 @@
|
||||||
|
+++
|
||||||
|
summary = "step-by-step guide to creating a pastebin with Rocket"
|
||||||
|
+++
|
||||||
|
|
||||||
# Pastebin Tutorial
|
# Pastebin Tutorial
|
||||||
|
|
||||||
This section of the guide is a tutorial intended to demonstrate how real-world
|
This section of the guide is a tutorial intended to demonstrate how real-world
|
||||||
|
@ -109,9 +113,9 @@ string with the specified contents. Rocket will take the string and return it as
|
||||||
the body of a fully formed HTTP response with `Content-Type: text/plain`. You
|
the body of a fully formed HTTP response with `Content-Type: text/plain`. You
|
||||||
can read more about how Rocket formulates responses in the [responses section]
|
can read more about how Rocket formulates responses in the [responses section]
|
||||||
of the guide or at the [API documentation for the Responder
|
of the guide or at the [API documentation for the Responder
|
||||||
trait](@api/rocket/response/trait.Responder.html).
|
trait](@api/master/rocket/response/trait.Responder.html).
|
||||||
|
|
||||||
[responses section]: ../responses
|
[responses section]: ../responses/
|
||||||
|
|
||||||
Remember that routes first need to be mounted before Rocket dispatches requests
|
Remember that routes first need to be mounted before Rocket dispatches requests
|
||||||
to them. To mount the `index` route, modify the main function so that it reads:
|
to them. To mount the `index` route, modify the main function so that it reads:
|
||||||
|
@ -249,7 +253,7 @@ Here's a first take at implementing the `retrieve` route. The route below takes
|
||||||
in an `<id>` as a dynamic path element. The handler uses the `id` to construct a
|
in an `<id>` as a dynamic path element. The handler uses the `id` to construct a
|
||||||
path to the paste inside `upload/`, and then attempts to open the file at that
|
path to the paste inside `upload/`, and then attempts to open the file at that
|
||||||
path, optionally returning the `File` if it exists. Rocket treats a `None`
|
path, optionally returning the `File` if it exists. Rocket treats a `None`
|
||||||
[Responder](@api/rocket/response/trait.Responder.html#provided-implementations)
|
[Responder](@api/master/rocket/response/trait.Responder.html#provided-implementations)
|
||||||
as a **404** error, which is exactly what we want to return when the requested
|
as a **404** error, which is exactly what we want to return when the requested
|
||||||
paste doesn't exist.
|
paste doesn't exist.
|
||||||
|
|
||||||
|
@ -297,8 +301,9 @@ opened. For instance, imagine that you later decide that a special file
|
||||||
user issues a `GET` request to `/_credentials.txt`, the server will read and
|
user issues a `GET` request to `/_credentials.txt`, the server will read and
|
||||||
return the `upload/_credentials.txt` file, leaking the sensitive information.
|
return the `upload/_credentials.txt` file, leaking the sensitive information.
|
||||||
This is a big problem; it's known as the [full path disclosure
|
This is a big problem; it's known as the [full path disclosure
|
||||||
attack](https://www.owasp.org/index.php/Full_Path_Disclosure), and Rocket
|
attack](https://owasp.org/www-community/attacks/Full_Path_Disclosure), and
|
||||||
provides the tools to prevent this and other kinds of attacks from happening.
|
Rocket provides the tools to prevent this and other kinds of attacks from
|
||||||
|
happening.
|
||||||
|
|
||||||
### The Solution
|
### The Solution
|
||||||
|
|
||||||
|
@ -315,7 +320,7 @@ paste IDs, `PasteId`, so we'll simply need to implement `FromParam` for
|
||||||
|
|
||||||
Here's the `FromParam` implementation for `PasteId` in `src/paste_id.rs`:
|
Here's the `FromParam` implementation for `PasteId` in `src/paste_id.rs`:
|
||||||
|
|
||||||
[`FromParam`]: @api/rocket/request/trait.FromParam.html
|
[`FromParam`]: @api/master/rocket/request/trait.FromParam.html
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rocket::request::FromParam;
|
use rocket::request::FromParam;
|
||||||
|
@ -404,7 +409,7 @@ async fn upload(paste: Data<'_>) -> std::io::Result<String> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`Data`]: @api/rocket/data/struct.Data.html
|
[`Data`]: @api/master/rocket/data/struct.Data.html
|
||||||
[data guard]: ../requests/#body-data
|
[data guard]: ../requests/#body-data
|
||||||
|
|
||||||
Your code should:
|
Your code should:
|
||||||
|
@ -467,14 +472,14 @@ We note the following Rocket APIs being used in our implementation:
|
||||||
* The [`UriDisplayPath`] derive, allowing `PasteId` to be used in [`uri!`].
|
* The [`UriDisplayPath`] derive, allowing `PasteId` to be used in [`uri!`].
|
||||||
* The [`uri!`] macro to crate type-safe, URL-safe URIs.
|
* The [`uri!`] macro to crate type-safe, URL-safe URIs.
|
||||||
|
|
||||||
[`Data::open()`]: @api/rocket/data/struct.Data.html#method.open
|
[`Data::open()`]: @api/master/rocket/data/struct.Data.html#method.open
|
||||||
[`Data`]: @api/rocket/data/struct.Data.html
|
[`Data`]: @api/master/rocket/data/struct.Data.html
|
||||||
[`DataStream`]: @api/rocket/data/struct.DataStream.html
|
[`DataStream`]: @api/master/rocket/data/enum.DataStream.html
|
||||||
[`DataStream::into_file()`]: @api/rocket/data/struct.DataStream.html#method.into_file
|
[`DataStream::into_file()`]: @api/master/rocket/data/enum.DataStream.html#method.into_file
|
||||||
[`uri!`]: @api/rocket/macro.uri.html
|
[`uri!`]: @api/master/rocket/macro.uri.html
|
||||||
[`kibibytes()`]: @api/rocket/data/trait.ToByteUnit.html#tymethod.kibibytes
|
[`kibibytes()`]: @api/master/rocket/data/trait.ToByteUnit.html#method.kibibytes
|
||||||
[`ToByteUnit`]: @api/rocket/data/trait.ToByteUnit.html
|
[`ToByteUnit`]: @api/master/rocket/data/trait.ToByteUnit.html
|
||||||
[`UriDisplayPath`]: @api/rocket/derive.UriDisplayPath.html
|
[`UriDisplayPath`]: @api/master/rocket/derive.UriDisplayPath.html
|
||||||
|
|
||||||
Ensure that the route is mounted at the root path:
|
Ensure that the route is mounted at the root path:
|
||||||
|
|
||||||
|
@ -536,10 +541,10 @@ through some of them to get a better feel for Rocket. Here are some ideas:
|
||||||
* Add a new route, `GET /<id>/<lang>` that syntax highlights the paste with ID
|
* Add a new route, `GET /<id>/<lang>` that syntax highlights the paste with ID
|
||||||
`<id>` for language `<lang>`. If `<lang>` is not a known language, do no
|
`<id>` for language `<lang>`. If `<lang>` is not a known language, do no
|
||||||
highlighting. Possibly validate `<lang>` with `FromParam`.
|
highlighting. Possibly validate `<lang>` with `FromParam`.
|
||||||
* Use the [`local` module](@api/rocket/local/) to write unit tests for your
|
* Use the [`local` module](@api/master/rocket/local/) to write unit tests for your
|
||||||
pastebin.
|
pastebin.
|
||||||
* Dispatch a thread before `launch`ing Rocket in `main` that periodically
|
* Dispatch a thread before `launch`ing Rocket in `main` that periodically
|
||||||
cleans up idling old pastes in `upload/`.
|
cleans up idling old pastes in `upload/`.
|
||||||
|
|
||||||
You can find the full source code for the [completed pastebin tutorial on
|
You can find the full source code for the [completed pastebin tutorial on
|
||||||
GitHub](@example/pastebin).
|
GitHub](@git/master/examples/pastebin).
|
|
@ -0,0 +1,25 @@
|
||||||
|
+++
|
||||||
|
summary = "next steps, and learning more about Rocket"
|
||||||
|
+++
|
||||||
|
|
||||||
|
# Conclusion
|
||||||
|
|
||||||
|
We hope you agree that Rocket is a refreshing take on web frameworks. As with
|
||||||
|
any software project, Rocket is _alive_. There are always things to improve, and
|
||||||
|
we're happy to take the best ideas. If you have something in mind, please
|
||||||
|
[submit an issue](https://github.com/rwf2/Rocket/issues).
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
If you find yourself having trouble developing Rocket applications, you can get
|
||||||
|
help via chat at [`#rocket:mozilla.org`] on Matrix. The [FAQ](../faq/) also
|
||||||
|
provides answers to commonly asked questions.
|
||||||
|
|
||||||
|
[`#rocket:mozilla.org`]: @chat
|
||||||
|
|
||||||
|
## What's next?
|
||||||
|
|
||||||
|
The best way to learn Rocket is to _build something_. It should be fun and easy,
|
||||||
|
and there's always someone to help. Alternatively, you can read through the
|
||||||
|
[Rocket examples](@git/master/examples) or the [Rocket source code](@git/master/core/lib/src).
|
||||||
|
Whatever you decide to do next, we hope you have a blast!
|
|
@ -1,3 +1,23 @@
|
||||||
|
+++
|
||||||
|
summary = "answers to frequently asked questions about Rocket and its usage"
|
||||||
|
+++
|
||||||
|
|
||||||
|
{% macro faq(id) %}
|
||||||
|
<details id="{{ id }}">
|
||||||
|
<summary>
|
||||||
|
<a class="anchor" href="#{{ id }}" title="anchor">#</a>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro answer() %}
|
||||||
|
</summary>
|
||||||
|
<div class="content">
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro endfaq() %}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
# FAQ
|
# FAQ
|
||||||
|
|
||||||
Below you'll find a collection of commonly asked questions and answers. If you
|
Below you'll find a collection of commonly asked questions and answers. If you
|
||||||
|
@ -8,12 +28,9 @@ discussion thread].
|
||||||
|
|
||||||
## About Rocket
|
## About Rocket
|
||||||
|
|
||||||
<details id="monolithic">
|
{{ faq("monolithic") }}
|
||||||
<summary>
|
|
||||||
Is Rocket a monolithic framework like Rails? Or is it more like Flask?
|
Is Rocket a monolithic framework like Rails? Or is it more like Flask?
|
||||||
<a class="headerlink" href="#monolithic" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
Neither!
|
Neither!
|
||||||
|
|
||||||
|
@ -38,13 +55,13 @@ Unlike other frameworks, Rocket makes it its mission to help you avoid security
|
||||||
and correctness blunders. It does this by including, out-of-the-box:
|
and correctness blunders. It does this by including, out-of-the-box:
|
||||||
|
|
||||||
* A flexible, type-based [configuration](../configuration/) system.
|
* A flexible, type-based [configuration](../configuration/) system.
|
||||||
* [Security and privacy headers](@api/rocket/shield/) by default.
|
* [Security and privacy headers](@api/master/rocket/shield/) by default.
|
||||||
* Zero-Copy RFC compliant [URI parsers](@api/rocket/http/uri).
|
* Zero-Copy RFC compliant [URI parsers](@api/master/rocket/http/uri).
|
||||||
* Safe, [typed URIs](@api/rocket/macro.uri.html) with compile-time checking.
|
* Safe, [typed URIs](@api/master/rocket/macro.uri.html) with compile-time checking.
|
||||||
* [Compile-time and launch-time route checking](@api/rocket/attr.route.html).
|
* [Compile-time and launch-time route checking](@api/master/rocket/attr.route.html).
|
||||||
* A [testing framework](@api/rocket/local) with sync and `async` variants.
|
* A [testing framework](@api/master/rocket/local) with sync and `async` variants.
|
||||||
* Safe, exclusive access to fully decoded HTTP values.
|
* Safe, exclusive access to fully decoded HTTP values.
|
||||||
* Mandatory [data limits](@api/rocket/data/struct.Limits.html) to prevent
|
* Mandatory [data limits](@api/master/rocket/data/struct.Limits.html) to prevent
|
||||||
trivial DoS attacks.
|
trivial DoS attacks.
|
||||||
|
|
||||||
Of course, this functionality comes at a compile-time cost (but notably, _not_
|
Of course, this functionality comes at a compile-time cost (but notably, _not_
|
||||||
|
@ -66,40 +83,26 @@ time can be further reduced by using faster linkers like `lld`. We think the
|
||||||
trade-off is worth it. Rocket will never compromise security, correctness, or
|
trade-off is worth it. Rocket will never compromise security, correctness, or
|
||||||
usability to "win" at benchmarks of any sort.
|
usability to "win" at benchmarks of any sort.
|
||||||
|
|
||||||
</div>
|
[`rocket_dyn_templates`]: @api/master/rocket_dyn_templates/
|
||||||
</details>
|
[`rocket_db_pools`]: @api/master/rocket_db_pools/
|
||||||
|
{{ endfaq() }}
|
||||||
|
|
||||||
[`rocket_dyn_templates`]: @api/rocket_dyn_templates
|
|
||||||
[`rocket_db_pools`]: @api/rocket_db_pools
|
|
||||||
|
|
||||||
<details id="compact">
|
{{ faq("compact") }}
|
||||||
<summary>
|
|
||||||
I want a small and compact web framework. Is Rocket it?
|
I want a small and compact web framework. Is Rocket it?
|
||||||
<a class="headerlink" href="#compact" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
We think so! See ["Is Rocket a monolithic framework like Rails?"](#monolithic)
|
We think so! See ["Is Rocket a monolithic framework like Rails?"](#monolithic)
|
||||||
</div>
|
{{ endfaq() }}
|
||||||
</details>
|
|
||||||
|
|
||||||
<details id="complete">
|
{{ faq("complete") }}
|
||||||
<summary>
|
|
||||||
I want a web framework with all the bells and whistles. Is Rocket it?
|
I want a web framework with all the bells and whistles. Is Rocket it?
|
||||||
<a class="headerlink" href="#complete" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
We think so! See ["Is Rocket a monolithic framework like Rails?"](#monolithic)
|
We think so! See ["Is Rocket a monolithic framework like Rails?"](#monolithic)
|
||||||
</div>
|
{{ endfaq() }}
|
||||||
</details>
|
|
||||||
|
|
||||||
<details id="in-prod">
|
{{ faq("in-prod") }}
|
||||||
<summary>
|
|
||||||
Can I use Rocket in production? Should I? It's only v0.x!
|
Can I use Rocket in production? Should I? It's only v0.x!
|
||||||
<a class="headerlink" href="#in-prod" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
We **enthusiastically** recommend using Rocket in production, with the following
|
We **enthusiastically** recommend using Rocket in production, with the following
|
||||||
non-exhaustive list of caveats:
|
non-exhaustive list of caveats:
|
||||||
|
@ -137,15 +140,11 @@ Furthermore, we backport _all_ security and correctness patches to the previous
|
||||||
major release (`0.{x-1}.y`), so your application remains secure if you need time
|
major release (`0.{x-1}.y`), so your application remains secure if you need time
|
||||||
to upgrade.
|
to upgrade.
|
||||||
|
|
||||||
</div>
|
{{ endfaq() }}
|
||||||
</details>
|
|
||||||
|
|
||||||
<details id="performance">
|
{{ faq("performance") }}
|
||||||
<summary>
|
|
||||||
Is Rocket slow? Is Rocket fast?
|
Is Rocket slow? Is Rocket fast?
|
||||||
<a class="headerlink" href="#performance" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
Rocket is pretty fast.
|
Rocket is pretty fast.
|
||||||
|
|
||||||
|
@ -184,18 +183,13 @@ zero-copy parsing and deserialization.
|
||||||
<small>* A common mistake is to pit against Rocket's "Hello, world!" without
|
<small>* A common mistake is to pit against Rocket's "Hello, world!" without
|
||||||
normalizing for response size, especially security headers.</small>
|
normalizing for response size, especially security headers.</small>
|
||||||
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
[managed state]: ../state/#managed-state
|
[managed state]: ../state/#managed-state
|
||||||
[request-local state]: ../state/#request-local-state
|
[request-local state]: ../state/#request-local-state
|
||||||
|
{{ endfaq() }}
|
||||||
|
|
||||||
<details id="showcase">
|
{{ faq("showcase") }}
|
||||||
<summary>
|
|
||||||
What are some examples of "big" apps written in Rocket?
|
What are some examples of "big" apps written in Rocket?
|
||||||
<a class="headerlink" href="#showcase" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
Here are some notable projects and websites in Rocket we're aware of:
|
Here are some notable projects and websites in Rocket we're aware of:
|
||||||
|
|
||||||
|
@ -213,20 +207,16 @@ you'd like to see here!
|
||||||
[Conduit]: https://conduit.rs/
|
[Conduit]: https://conduit.rs/
|
||||||
[Rust-Lang.org]: https://www.rust-lang.org/
|
[Rust-Lang.org]: https://www.rust-lang.org/
|
||||||
[Plume]: https://github.com/Plume-org/Plume
|
[Plume]: https://github.com/Plume-org/Plume
|
||||||
[Hagrid]: https://gitlab.com/hagrid-keyserver/hagrid/
|
[Hagrid]: https://gitlab.com/keys.openpgp.org/hagrid
|
||||||
[SourceGraph Syntax Highlighter]: https://github.com/sourcegraph/sourcegraph/tree/main/docker-images/syntax-highlighter
|
[SourceGraph Syntax Highlighter]: https://github.com/sourcegraph/sourcegraph/tree/main/docker-images/syntax-highlighter
|
||||||
[Let us know]: https://github.com/rwf2/Rocket/discussions/categories/show-and-tell
|
[Let us know]: https://github.com/rwf2/Rocket/discussions/categories/show-and-tell
|
||||||
[Revolt]: https://github.com/revoltchat/backend
|
[Revolt]: https://github.com/revoltchat/backend
|
||||||
|
{{ endfaq() }}
|
||||||
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details id="releases">
|
{{ faq("releases") }}
|
||||||
<summary>
|
|
||||||
When will version `$y` be released? Why does it take so long?
|
When will version `$y` be released? Why does it take so long?
|
||||||
<a class="headerlink" href="#releases" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
Rocket represents an ecosystem-wide effort to create a web framework that
|
Rocket represents an ecosystem-wide effort to create a web framework that
|
||||||
enables writing web applications with unparalleled security, performance, and
|
enables writing web applications with unparalleled security, performance, and
|
||||||
|
@ -242,14 +232,14 @@ For example, work for Rocket v0.5 included:
|
||||||
* [Reporting multiple](https://github.com/bikeshedder/deadpool/issues/114)
|
* [Reporting multiple](https://github.com/bikeshedder/deadpool/issues/114)
|
||||||
[correctness issues](https://github.com/bikeshedder/deadpool/issues/113) in `deadpool`.
|
[correctness issues](https://github.com/bikeshedder/deadpool/issues/113) in `deadpool`.
|
||||||
* [Fixing a major usability issue in `async-stream`.](https://github.com/tokio-rs/async-stream/pull/57)
|
* [Fixing a major usability issue in `async-stream`.](https://github.com/tokio-rs/async-stream/pull/57)
|
||||||
* [Creating a brand new configuration library.](https://github.com/rwf2/Figment)
|
* [Creating a brand new configuration library.](https://github.com/SergioBenitez/Figment)
|
||||||
* [Updating](https://github.com/rousan/multer-rs/pull/21),
|
* [Updating](https://github.com/rousan/multer-rs/pull/21),
|
||||||
[fixing](https://github.com/rousan/multer-rs/pull/29), and
|
[fixing](https://github.com/rousan/multer-rs/pull/29), and
|
||||||
[maintaining](https://github.com/rousan/multer-rs/commit/2758e778e6aa2785b737c82fe45e58026bea2f01) `multer`.
|
[maintaining](https://github.com/rousan/multer-rs/commit/2758e778e6aa2785b737c82fe45e58026bea2f01) `multer`.
|
||||||
* [Significantly improving `async_trait` correctness and usability.](https://github.com/dtolnay/async-trait/pull/143)
|
* [Significantly improving `async_trait` correctness and usability.](https://github.com/dtolnay/async-trait/pull/143)
|
||||||
* [Porting `Pattern` APIs to stable.](https://github.com/rwf2/stable-pattern)
|
* [Porting `Pattern` APIs to stable.](https://github.com/SergioBenitez/stable-pattern)
|
||||||
* [Porting macro diagnostics to stable.](https://github.com/rwf2/proc-macro2-diagnostics)
|
* [Porting macro diagnostics to stable.](https://github.com/SergioBenitez/proc-macro2-diagnostics)
|
||||||
* [Creating a brand new byte unit library.](https://github.com/rwf2/ubyte)
|
* [Creating a brand new byte unit library.](https://github.com/SergioBenitez/ubyte)
|
||||||
* [Fixing a bug in `rustc`'s `libtest`.](https://github.com/rust-lang/rust/pull/78227)
|
* [Fixing a bug in `rustc`'s `libtest`.](https://github.com/rust-lang/rust/pull/78227)
|
||||||
|
|
||||||
A version of Rocket is released whenever it is feature-complete and exceeds
|
A version of Rocket is released whenever it is feature-complete and exceeds
|
||||||
|
@ -259,21 +249,17 @@ a release if these properties are not readily evident.
|
||||||
|
|
||||||
We know it can be frustrating, but we hope you'll agree that Rocket is worth the
|
We know it can be frustrating, but we hope you'll agree that Rocket is worth the
|
||||||
wait.
|
wait.
|
||||||
|
{{ endfaq() }}
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## How To
|
## How To
|
||||||
|
|
||||||
<details id="web-sockets">
|
{{ faq("web-sockets") }}
|
||||||
<summary>
|
|
||||||
Can I, and if so how, do I use WebSockets?
|
Can I, and if so how, do I use WebSockets?
|
||||||
<a class="headerlink" href="#web-sockets" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
You can! WebSocket support is provided by the officially maintained
|
You can! WebSocket support is provided by the officially maintained
|
||||||
[`rocket_ws`](@api/rocket_ws) crate. You'll find all the docs you need there.
|
[`rocket_ws`](@api/master/rocket_ws/) crate. You'll find all the docs you need
|
||||||
|
there.
|
||||||
|
|
||||||
Rocket _also_ supports [Server-Sent Events], which allows for real-time
|
Rocket _also_ supports [Server-Sent Events], which allows for real-time
|
||||||
_unidirectional_ communication from the server to the client. The protocol is a
|
_unidirectional_ communication from the server to the client. The protocol is a
|
||||||
|
@ -281,19 +267,20 @@ bit simpler, and you may find SSE sufficient for your use-case. For instance,
|
||||||
the [chat example] uses SSE to implement a real-time, multiroom chat
|
the [chat example] uses SSE to implement a real-time, multiroom chat
|
||||||
application.
|
application.
|
||||||
|
|
||||||
</div>
|
That being said, Rocket _does_ suport [Server-Sent Events], which allows for
|
||||||
</details>
|
real-time _unidirectional_ communication from the server to the client. This is
|
||||||
|
often sufficient for many of the applications that WebSockets are typically used
|
||||||
|
for. For instance, the [chat example] uses SSE to implement a real-time,
|
||||||
|
multiroom chat application.
|
||||||
|
|
||||||
[working on it]: https://github.com/rwf2/Rocket/issues/90
|
[working on it]: https://github.com/rwf2/Rocket/issues/90
|
||||||
[Server-Sent Events]: @api/rocket/response/stream/struct.EventStream.html
|
[Server-Sent Events]: @api/master/rocket/response/stream/struct.EventStream.html
|
||||||
[chat example]: @example/chat
|
[chat example]: @git/master/examples/chat
|
||||||
|
{{ endfaq() }}
|
||||||
|
|
||||||
<details id="global-state">
|
{{ faq("global-state") }}
|
||||||
<summary>
|
|
||||||
Should I use global state via something like `lazy_static!`?
|
Should I use global state via something like `lazy_static!`?
|
||||||
<a class="headerlink" href="#global-state" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
No. Rocket's [managed state] provides a better alternative.
|
No. Rocket's [managed state] provides a better alternative.
|
||||||
|
|
||||||
|
@ -305,17 +292,13 @@ numerous. They include:
|
||||||
state.
|
state.
|
||||||
* The inability to know the state a route accesses by looking at its
|
* The inability to know the state a route accesses by looking at its
|
||||||
signature.
|
signature.
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
[managed state]: ../state/#managed-state
|
[managed state]: ../state/#managed-state
|
||||||
|
{{ endfaq() }}
|
||||||
|
|
||||||
<details id="file-uploads">
|
{{ faq("file-uploads") }}
|
||||||
<summary>
|
|
||||||
How do I handle file uploads? What is this "multipart" in my stream?
|
How do I handle file uploads? What is this "multipart" in my stream?
|
||||||
<a class="headerlink" href="#file-uploads" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
For a quick example on how to handle file uploads, see [multipart forms]. The
|
For a quick example on how to handle file uploads, see [multipart forms]. The
|
||||||
gist is: use `Form<TempFile>` as a data guard.
|
gist is: use `Form<TempFile>` as a data guard.
|
||||||
|
@ -325,24 +308,20 @@ The raw stream, as seen by [`Data`] for example, thus contains the necessary
|
||||||
metadata to encode the form. Rocket's [`Form`] data guard can parse these form
|
metadata to encode the form. Rocket's [`Form`] data guard can parse these form
|
||||||
submissions into any type that implements [`FromForm`]. This includes types like
|
submissions into any type that implements [`FromForm`]. This includes types like
|
||||||
[`TempFile`] which streams the decoded data to disk for persistence.
|
[`TempFile`] which streams the decoded data to disk for persistence.
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
[multipart]: https://datatracker.ietf.org/doc/html/rfc7578
|
[multipart]: https://datatracker.ietf.org/doc/html/rfc7578
|
||||||
[multipart forms]: ../requests/#multipart
|
[multipart forms]: ../requests/#multipart
|
||||||
[`DataField`]: @api/rocket/form/struct.DataField.html
|
[`DataField`]: @api/master/rocket/form/struct.DataField.html
|
||||||
[`TempFile`]: @api/rocket/fs/enum.TempFile.html
|
[`TempFile`]: @api/master/rocket/fs/enum.TempFile.html
|
||||||
[`DataField`]: @api/rocket/data/struct.Data.html
|
[`DataField`]: @api/master/rocket/data/struct.Data.html
|
||||||
[`Form`]: @api/rocket/form/struct.Form.html
|
[`Form`]: @api/master/rocket/form/struct.Form.html
|
||||||
[`FromForm`]: @api/rocket/form/trait.FromForm.html
|
[`FromForm`]: @api/master/rocket/form/trait.FromForm.html
|
||||||
[`Data`]: @api/rocket/struct.Data.html
|
[`Data`]: @api/master/rocket/struct.Data.html
|
||||||
|
{{ endfaq() }}
|
||||||
|
|
||||||
<details id="raw-request">
|
{{ faq("raw-request") }}
|
||||||
<summary>
|
|
||||||
How do I get an `&Request` in a handler?
|
How do I get an `&Request` in a handler?
|
||||||
<a class="headerlink" href="#raw-request" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
You don't!
|
You don't!
|
||||||
|
|
||||||
|
@ -364,22 +343,18 @@ out-of-the-box, and you can implement your own, too. See the following:
|
||||||
* Data Guards: [`FromData`]
|
* Data Guards: [`FromData`]
|
||||||
* Form Guards: [`FromForm`]
|
* Form Guards: [`FromForm`]
|
||||||
* Request Guards: [`FromRequest`]
|
* Request Guards: [`FromRequest`]
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
[philosophy]: ../introduction/#foreword
|
[philosophy]: ../introduction/#foreword
|
||||||
[`FromParam`]: @api/rocket/request/trait.FromParam.html
|
[`FromParam`]: @api/master/rocket/request/trait.FromParam.html
|
||||||
[`FromSegments`]: @api/rocket/request/trait.FromSegments.html
|
[`FromSegments`]: @api/master/rocket/request/trait.FromSegments.html
|
||||||
[`FromData`]: @api/rocket/data/trait.FromData.html
|
[`FromData`]: @api/master/rocket/data/trait.FromData.html
|
||||||
[`FromForm`]: @api/rocket/form/trait.FromForm.html
|
[`FromForm`]: @api/master/rocket/form/trait.FromForm.html
|
||||||
[`FromRequest`]: @api/rocket/request/trait.FromRequest.html
|
[`FromRequest`]: @api/master/rocket/request/trait.FromRequest.html
|
||||||
|
{{ endfaq() }}
|
||||||
|
|
||||||
<details id="response-headers">
|
{{ faq("response-headers") }}
|
||||||
<summary>
|
|
||||||
How do I add a header to a response?
|
How do I add a header to a response?
|
||||||
<a class="headerlink" href="#response-headers" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
That depends on the header!
|
That depends on the header!
|
||||||
|
|
||||||
|
@ -404,7 +379,7 @@ details setting a custom `Content-Type` or overriding an existing one.
|
||||||
**Everything Else**
|
**Everything Else**
|
||||||
|
|
||||||
To add a custom header, you'll need a custom [`Responder`]. Not to worry!
|
To add a custom header, you'll need a custom [`Responder`]. Not to worry!
|
||||||
[`Responder` can be derived](@api/rocket/derive.Responder.html) in almost all
|
[`Responder` can be derived](@api/master/rocket/derive.Responder.html) in almost all
|
||||||
cases. If a type for the header you want to add already exists, you can directly
|
cases. If a type for the header you want to add already exists, you can directly
|
||||||
derive `Responder` for a struct that contains the header value, which adds the
|
derive `Responder` for a struct that contains the header value, which adds the
|
||||||
header to the response:
|
header to the response:
|
||||||
|
@ -461,21 +436,16 @@ impl<'r> Responder<'r, 'static> for Person {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
</div>
|
[`Responder`]: @api/master/rocket/response/trait.Responder.html
|
||||||
</details>
|
[`content`]: @api/master/rocket/response/content/index.html
|
||||||
|
[`status`]: @api/master/rocket/response/status/index.html
|
||||||
|
[`Header`]: @api/master/rocket/http/struct.Header.html
|
||||||
|
[`Json`]: @api/master/rocket/serde/json/struct.Json.html
|
||||||
|
{{ endfaq() }}
|
||||||
|
|
||||||
[`Responder`]: @api/rocket/response/trait.Responder.html
|
{{ faq("multiple-responses") }}
|
||||||
[`content`]: @api/rocket/response/content/index.html
|
|
||||||
[`status`]: @api/rocket/response/status/index.html
|
|
||||||
[`Header`]: @api/rocket/http/struct.Header.html
|
|
||||||
[`Json`]: @api/rocket/serde/json/struct.Json.html
|
|
||||||
|
|
||||||
<details id="multiple-responses">
|
|
||||||
<summary>
|
|
||||||
How do I make one handler return different responses or status codes?
|
How do I make one handler return different responses or status codes?
|
||||||
<a class="headerlink" href="#multiple-responses" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
If you're returning _two_ different responses, use a `Result<T, E>` or an
|
If you're returning _two_ different responses, use a `Result<T, E>` or an
|
||||||
[`Either<A, B>`].
|
[`Either<A, B>`].
|
||||||
|
@ -498,18 +468,13 @@ enum Error<'r, T> {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
[`Either<A, B>`]: https://docs.rs/either/1/either/enum.Either.html
|
[`Either<A, B>`]: https://docs.rs/either/1/either/enum.Either.html
|
||||||
[derive a custom `Responder`]: @api/rocket/derive.Responder.html
|
[derive a custom `Responder`]: @api/master/rocket/derive.Responder.html
|
||||||
|
{{ endfaq() }}
|
||||||
|
|
||||||
<details id="automatic-reload">
|
{{ faq("automatic-reload") }}
|
||||||
<summary>
|
|
||||||
How do I make Rocket reload automatically when I change source code?
|
How do I make Rocket reload automatically when I change source code?
|
||||||
<a class="headerlink" href="#automatic-reload" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
In debug mode, Rocket automatically reloads templates for you. So if all you
|
In debug mode, Rocket automatically reloads templates for you. So if all you
|
||||||
need is live template reloading, Rocket's got you covered.
|
need is live template reloading, Rocket's got you covered.
|
||||||
|
@ -523,20 +488,16 @@ cargo watch -x run
|
||||||
```
|
```
|
||||||
|
|
||||||
To only restart on successful compilations, see [this note].
|
To only restart on successful compilations, see [this note].
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
[`cargo-watch`]: https://github.com/watchexec/cargo-watch
|
[`cargo-watch`]: https://github.com/watchexec/cargo-watch
|
||||||
[`watchexec`]: https://github.com/watchexec/watchexec
|
[`watchexec`]: https://github.com/watchexec/watchexec
|
||||||
[`entr`]: http://eradman.com/entrproject/
|
[`entr`]: http://eradman.com/entrproject/
|
||||||
[this note]: https://github.com/watchexec/cargo-watch/tree/b75ce2c260874dea480f4accfd46ab28709ec56a#restarting-an-application-only-if-the-buildcheck-succeeds
|
[this note]: https://github.com/watchexec/cargo-watch/tree/b75ce2c260874dea480f4accfd46ab28709ec56a#restarting-an-application-only-if-the-buildcheck-succeeds
|
||||||
|
{{ endfaq() }}
|
||||||
|
|
||||||
<details id="external-managed-state">
|
{{ faq("external-managed-state") }}
|
||||||
<summary>
|
|
||||||
How do I access managed state outside of a Rocket-related context?
|
How do I access managed state outside of a Rocket-related context?
|
||||||
<a class="headerlink" href="#external-managed-state" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
Use an `Arc`, like this:
|
Use an `Arc`, like this:
|
||||||
|
|
||||||
|
@ -558,15 +519,11 @@ fn rocket() -> _ {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
</div>
|
{{ endfaq() }}
|
||||||
</details>
|
|
||||||
|
|
||||||
<details id="internal-server">
|
{{ faq("internal-server") }}
|
||||||
<summary>
|
|
||||||
How do I make Rocket a _part_ of my application as opposed to the whole thing?
|
How do I make Rocket a _part_ of my application as opposed to the whole thing?
|
||||||
<a class="headerlink" href="#internal-server" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
Use the `#[main]` attribute and manually call [`launch()`]:
|
Use the `#[main]` attribute and manually call [`launch()`]:
|
||||||
|
|
||||||
|
@ -585,19 +542,14 @@ async fn main() {
|
||||||
The cost to using the attribute is imperceptible and guarantees compatibility
|
The cost to using the attribute is imperceptible and guarantees compatibility
|
||||||
with Rocket's async I/O.
|
with Rocket's async I/O.
|
||||||
|
|
||||||
</div>
|
[`launch()`]: @api/master/rocket/struct.Rocket.html#method.launch
|
||||||
</details>
|
{{ endfaq() }}
|
||||||
|
|
||||||
[`launch()`]: @api/rocket/struct.Rocket.html#method.launch
|
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
||||||
<details id="broken-example">
|
{{ faq("broken-example") }}
|
||||||
<summary>
|
|
||||||
Is example `foo` broken? It doesn't work for me.
|
Is example `foo` broken? It doesn't work for me.
|
||||||
<a class="headerlink" href="#broken-example" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
Almost certainly not.
|
Almost certainly not.
|
||||||
|
|
||||||
|
@ -612,15 +564,11 @@ Common mistakes when running examples include:
|
||||||
* Looking at outdated examples on StackOverflow or Google. Check the
|
* Looking at outdated examples on StackOverflow or Google. Check the
|
||||||
date/version!
|
date/version!
|
||||||
* Not configuring the correct dependencies. See the example's `Cargo.toml`!
|
* Not configuring the correct dependencies. See the example's `Cargo.toml`!
|
||||||
</div>
|
{{ endfaq() }}
|
||||||
</details>
|
|
||||||
|
|
||||||
<details id="unsat-bound">
|
{{ faq("unsat-bound") }}
|
||||||
<summary>
|
|
||||||
The trait bound `rocket::Responder` (`FromRequest`, etc.) is not satisfied.
|
The trait bound `rocket::Responder` (`FromRequest`, etc.) is not satisfied.
|
||||||
<a class="headerlink" href="#unsat-bound" title="permalink">#</a>
|
{{ answer() }}
|
||||||
</summary>
|
|
||||||
<div class="content">
|
|
||||||
|
|
||||||
If you're fairly certain a type implements a given Rocket trait but still get an
|
If you're fairly certain a type implements a given Rocket trait but still get an
|
||||||
error like:
|
error like:
|
||||||
|
@ -658,6 +606,4 @@ implement the trait from the other library (since it is considered to be a
|
||||||
_different_, _distinct_ library). In other words, you can _never_ mix two
|
_different_, _distinct_ library). In other words, you can _never_ mix two
|
||||||
different published versions of Rocket, a published version and a `git` version,
|
different published versions of Rocket, a published version and a `git` version,
|
||||||
or two instances from different `git` revisions.
|
or two instances from different `git` revisions.
|
||||||
|
{{ endfaq() }}
|
||||||
</div>
|
|
||||||
</details>
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# The Rocket Programming Guide
|
||||||
|
|
||||||
|
Welcome to Rocket!
|
||||||
|
|
||||||
|
This is the official guide for Rocket v0.6. It is designed to serve as a
|
||||||
|
starting point to 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 purely technical documentation with examples, see
|
||||||
|
the [API documentation](@api/master/rocket).
|
||||||
|
|
||||||
|
The guide is split into several sections, each with a focus on a different
|
||||||
|
aspect of Rocket. The sections are:
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
The official community support channels are via Matrix chat on
|
||||||
|
[`#rocket:mozilla.org`] and via [GitHub Discussions]. To join us on Matrix, we
|
||||||
|
recommend the browser-based [Element] client. The [FAQ](faq/) also provides
|
||||||
|
answers to commonly asked questions.
|
||||||
|
|
||||||
|
[`#rocket:mozilla.org`]: @chat
|
||||||
|
[GitHub Discussions]: https://github.com/rwf2/Rocket/discussions
|
||||||
|
[Element]: https://chat.mozilla.org/#/room/#rocket:mozilla.org
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "rocket_guide_tests"
|
name = "rocket_docs_tests"
|
||||||
version = "0.6.0-dev"
|
version = "0.6.0-dev"
|
||||||
workspace = "../../"
|
workspace = "../../"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
@ -10,8 +10,9 @@ rocket = { path = "../../core/lib", features = ["secrets"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rocket = { path = "../../core/lib", features = ["secrets", "json", "mtls"] }
|
rocket = { path = "../../core/lib", features = ["secrets", "json", "mtls"] }
|
||||||
rand = "0.8"
|
|
||||||
figment = { version = "0.10", features = ["toml", "env"] }
|
figment = { version = "0.10", features = ["toml", "env"] }
|
||||||
|
tokio = { version = "1", features = ["macros", "io-std"] }
|
||||||
|
rand = "0.8"
|
||||||
|
|
||||||
[dev-dependencies.rocket_dyn_templates]
|
[dev-dependencies.rocket_dyn_templates]
|
||||||
path = "../../contrib/dyn_templates"
|
path = "../../contrib/dyn_templates"
|
|
@ -0,0 +1 @@
|
||||||
|
rocket::internal_guide_tests!("../guide/*.md");
|
|
@ -1,5 +1,5 @@
|
||||||
#[cfg(any(test, doctest))] rocket::internal_guide_tests!("../guide/*.md");
|
#[cfg(any(test, doctest))] mod guide;
|
||||||
#[cfg(any(test, doctest))] rocket::internal_guide_tests!("../../README.md");
|
#[cfg(any(test, doctest))] mod readme;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! map {
|
macro_rules! map {
|
|
@ -0,0 +1 @@
|
||||||
|
rocket::internal_guide_tests!("../../README.md");
|
|
@ -35,10 +35,8 @@ popd > /dev/null 2>&1
|
||||||
echo ":::: Generating redirects..."
|
echo ":::: Generating redirects..."
|
||||||
REDIRECTS="
|
REDIRECTS="
|
||||||
/ /v0.5/rocket/ 302!
|
/ /v0.5/rocket/ 302!
|
||||||
/v0.4 https://docs.rs/rocket/0.4/rocket/
|
/rocket/ /v0.5/rocket/ 302!
|
||||||
/v0.4/:crate/* https://docs.rs/:crate/0.4/:crate/:splat
|
|
||||||
/:v /:v/rocket/
|
/:v /:v/rocket/
|
||||||
/v0.5/* https://v0-5--rocket-docs.netlify.app/:splat 200
|
|
||||||
/:v/* https://:v--rocket-docs.netlify.app/:splat 200
|
/:v/* https://:v--rocket-docs.netlify.app/:splat 200
|
||||||
"
|
"
|
||||||
|
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
# Rocket Website Source
|
|
||||||
|
|
||||||
This directory contains the source files for the content on [Rocket's
|
|
||||||
website](https://rocket.rs).
|
|
||||||
|
|
||||||
## Contents
|
|
||||||
|
|
||||||
This directory contains the following:
|
|
||||||
|
|
||||||
* `index.toml` - Source data for the index.
|
|
||||||
* `overview.toml` - Source data for the overview page (`overview/`).
|
|
||||||
* `news/index.toml` - Source data for the news page (`news/`).
|
|
||||||
* `news/*.md` - News articles linked to from `news/index.toml`.
|
|
||||||
* `guide/*.md` - Guide pages linked to from `guide.md`.
|
|
||||||
|
|
||||||
[Rocket Programming Guide]: https://rocket.rs/master/guide/
|
|
||||||
|
|
||||||
### Guide Links
|
|
||||||
|
|
||||||
Cross-linking guide pages is accomplished via relative links. Outside of the
|
|
||||||
index, this is: `../{page}#anchor`. For instance, to link to the **Quickstart >
|
|
||||||
Running Examples** page, use `../quickstart#running-examples`.
|
|
||||||
|
|
||||||
### Aliases
|
|
||||||
|
|
||||||
Aliases are shorthand URLs that start with `@` (e.g, `@api`). They are used
|
|
||||||
throughout the guide to simplify versioning URLs to Rocket's source code and the
|
|
||||||
Rocket API. They are replaced at build time with a URL prefix. At present, the
|
|
||||||
following aliases are available, where `${version}` is Rocket's version string
|
|
||||||
at the time of compilation:
|
|
||||||
|
|
||||||
* `@example`: https://github.com/rwf2/Rocket/tree/${version}/examples
|
|
||||||
* `@github`: https://github.com/rwf2/Rocket/tree/${version}
|
|
||||||
* `@api`: https://api.rocket.rs/${version}
|
|
||||||
|
|
||||||
For example, to link to `Rocket::launch()`, you might write:
|
|
||||||
|
|
||||||
```md
|
|
||||||
Launch an instance of your application using the [`launch()`] method.
|
|
||||||
|
|
||||||
[`launch()`]: @api/rocket/struct.Rocket.html#method.launch
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
The Rocket website source is licensed under the [GNU General Public License v3.0](LICENSE).
|
|
|
@ -1,14 +0,0 @@
|
||||||
# Upgrading
|
|
||||||
|
|
||||||
This a placeholder for an eventual migration guide from v0.5 to v0.6.
|
|
||||||
|
|
||||||
## Getting Help
|
|
||||||
|
|
||||||
If you run into any issues upgrading, we encourage you to ask questions via
|
|
||||||
[GitHub discussions] or via chat at [`#rocket:mozilla.org`] on Matrix or the
|
|
||||||
bridged [`#rocket`] IRC channel at `irc.libera.chat`. The [FAQ](../faq/) also
|
|
||||||
provides answers to commonly asked questions.
|
|
||||||
|
|
||||||
[GitHub discussions]: https://github.com/rwf2/Rocket/discussions
|
|
||||||
[`#rocket:mozilla.org`]: https://chat.mozilla.org/#/room/#rocket:mozilla.org
|
|
||||||
[`#rocket`]: https://kiwiirc.com/client/irc.libera.chat/#rocket
|
|
|
@ -1,27 +0,0 @@
|
||||||
# Conclusion
|
|
||||||
|
|
||||||
We hope you agree that Rocket is a refreshing take on web frameworks. As with
|
|
||||||
any software project, Rocket is _alive_. There are always things to improve, and
|
|
||||||
we're happy to take the best ideas. If you have something in mind, please
|
|
||||||
[submit an issue](https://github.com/rwf2/Rocket/issues).
|
|
||||||
|
|
||||||
## Getting Help
|
|
||||||
|
|
||||||
If you find yourself having trouble developing Rocket applications, you can get
|
|
||||||
help via chat at [`#rocket:mozilla.org`] on Matrix or the bridged [`#rocket`]
|
|
||||||
IRC channel on Libera.Chat at `irc.libera.chat`. We recommend joining us on
|
|
||||||
[Matrix via Element]. If you prefer IRC, you can join via the [Kiwi IRC client]
|
|
||||||
or a client of your own. The [FAQ](../faq/) also provides answers to commonly
|
|
||||||
asked questions.
|
|
||||||
|
|
||||||
[`#rocket:mozilla.org`]: https://chat.mozilla.org/#/room/#rocket:mozilla.org
|
|
||||||
[`#rocket`]: https://kiwiirc.com/client/irc.libera.chat/#rocket
|
|
||||||
[Matrix via Element]: https://chat.mozilla.org/#/room/#rocket:mozilla.org
|
|
||||||
[Kiwi IRC Client]: https://kiwiirc.com/client/irc.libera.chat/#rocket
|
|
||||||
|
|
||||||
## What's next?
|
|
||||||
|
|
||||||
The best way to learn Rocket is to _build something_. It should be fun and easy,
|
|
||||||
and there's always someone to help. Alternatively, you can read through the
|
|
||||||
[Rocket examples](@example) or the [Rocket source code](@github/core/lib/src).
|
|
||||||
Whatever you decide to do next, we hope you have a blast!
|
|
|
@ -1,46 +0,0 @@
|
||||||
# The Rocket Programming Guide
|
|
||||||
|
|
||||||
Welcome to Rocket!
|
|
||||||
|
|
||||||
This is the official guide for Rocket master. It is designed to serve as a
|
|
||||||
starting point to 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 purely technical documentation with examples, see
|
|
||||||
the [API documentation](@api).
|
|
||||||
|
|
||||||
The guide is split into several sections, each with a focus on a different
|
|
||||||
aspect of Rocket. The sections are:
|
|
||||||
|
|
||||||
- **[Introduction](introduction/):** introduces Rocket and its philosophy.
|
|
||||||
- **[Quickstart](quickstart/):** presents the minimal steps necessary to
|
|
||||||
run your first Rocket application.
|
|
||||||
- **[Upgrading from v0.5](upgrading/):** a migration guide from v0.5 to v0.6.
|
|
||||||
- **[Getting Started](getting-started/):** a gentle introduction to getting
|
|
||||||
your first Rocket application running.
|
|
||||||
- **[Overview](overview/):** describes the core concepts of Rocket.
|
|
||||||
- **[Requests](requests/):** discusses handling requests: control-flow,
|
|
||||||
parsing, and validating.
|
|
||||||
- **[Responses](responses/):** discusses generating responses.
|
|
||||||
- **[State](state/):** how to manage state in a Rocket application.
|
|
||||||
- **[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.
|
|
||||||
- **[Pastebin Tutorial](pastebin-tutorial/):** a tutorial creating a pastebin
|
|
||||||
with Rocket.
|
|
||||||
- **[Conclusion](conclusion/):** concludes the guide and discusses next steps
|
|
||||||
for learning.
|
|
||||||
- **[FAQ](faq/):** answers to frequently asked questions about Rocket and
|
|
||||||
using it.
|
|
||||||
|
|
||||||
## Getting Help
|
|
||||||
|
|
||||||
The official community support channels are via Matrix chat on
|
|
||||||
[`#rocket:mozilla.org`] and via [GitHub Discussions]. To join us on Matrix, we
|
|
||||||
recommend the browser-based [Element] client. The [FAQ](faq/) also provides
|
|
||||||
answers to commonly asked questions.
|
|
||||||
|
|
||||||
[GitHub Discussions]: https://github.com/rwf2/Rocket/discussions
|
|
||||||
[`#rocket:mozilla.org`]: https://chat.mozilla.org/#/room/#rocket:mozilla.org
|
|
||||||
[Element]: https://chat.mozilla.org/#/room/#rocket:mozilla.org
|
|
446
site/index.toml
446
site/index.toml
|
@ -1,446 +0,0 @@
|
||||||
###############################################################################
|
|
||||||
# Release info: displayed between bars in the header
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
[release]
|
|
||||||
version = "0.5.0"
|
|
||||||
date = "Nov 17, 2023"
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Top features: displayed in the header under the introductory text.
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
[[top_features]]
|
|
||||||
title = "Type Safe"
|
|
||||||
text = "Type safety turned up to 11 means security and robustness come at compile-time."
|
|
||||||
image = "helmet"
|
|
||||||
button = "Learn More"
|
|
||||||
url = "overview/#how-rocket-works"
|
|
||||||
width = "69px"
|
|
||||||
height = "71px"
|
|
||||||
|
|
||||||
[[top_features]]
|
|
||||||
title = "Boilerplate Free"
|
|
||||||
text = "Spend your time writing code that really matters and let Rocket handle the rest."
|
|
||||||
image = "robot-free"
|
|
||||||
button = "See Examples"
|
|
||||||
url = "overview/#anatomy-of-a-rocket-application"
|
|
||||||
width = "78px"
|
|
||||||
height = "71px"
|
|
||||||
|
|
||||||
[[top_features]]
|
|
||||||
title = "Easy To Use"
|
|
||||||
text = "Simple, intuitive APIs make Rocket approachable, no matter your background."
|
|
||||||
image = "sun"
|
|
||||||
button = "Get Started"
|
|
||||||
url = "guide"
|
|
||||||
margin = 2
|
|
||||||
width = "68px"
|
|
||||||
height = "69px"
|
|
||||||
|
|
||||||
[[top_features]]
|
|
||||||
title = "Extensible"
|
|
||||||
text = "Create your own first-class primitives that any Rocket application can use."
|
|
||||||
image = "telescope"
|
|
||||||
button = "See How"
|
|
||||||
url = "overview/#anatomy-of-a-rocket-application"
|
|
||||||
margin = 9
|
|
||||||
width = "71px"
|
|
||||||
height = "62px"
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Sections: make sure there are an odd number so colors work out.
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
[[sections]]
|
|
||||||
title = "Hello, Rocket!"
|
|
||||||
code = '''
|
|
||||||
#[macro_use] extern crate rocket;
|
|
||||||
|
|
||||||
#[get("/hello/<name>/<age>")]
|
|
||||||
fn hello(name: &str, age: u8) -> String {
|
|
||||||
format!("Hello, {} year old named {}!", age, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[launch]
|
|
||||||
fn rocket() -> _ {
|
|
||||||
rocket::build().mount("/", routes![hello])
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
text = '''
|
|
||||||
This is a **complete Rocket application**. It does exactly what you would
|
|
||||||
expect. If you were to visit **/hello/John/58**, you’d see:
|
|
||||||
|
|
||||||
<span class="callout">Hello, 58 year old named John!</span>
|
|
||||||
|
|
||||||
If someone visits a path with an `<age>` that isn’t a `u8`, Rocket doesn’t
|
|
||||||
just call `hello`. Instead, it tries other matching routes or returns a
|
|
||||||
**404**.
|
|
||||||
'''
|
|
||||||
|
|
||||||
[[sections]]
|
|
||||||
title = "Forms? Check!"
|
|
||||||
code = '''
|
|
||||||
#[derive(FromForm)]
|
|
||||||
struct Task<'r> {
|
|
||||||
#[field(validate = len(1..))]
|
|
||||||
description: &'r str,
|
|
||||||
completed: bool
|
|
||||||
}
|
|
||||||
|
|
||||||
#[post("/", data = "<task>")]
|
|
||||||
fn new(task: Form<Task<'_>>) -> Flash<Redirect> {
|
|
||||||
Flash::success(Redirect::to(uri!(home)), "Task added.")
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
text = '''
|
|
||||||
Form handling **is simple, declarative, and complete**: derive
|
|
||||||
[`FromForm`](@api/rocket/derive.FromForm.html) for your structure and set the
|
|
||||||
`data` parameter to a `Form` type. Rocket automatically **parses and
|
|
||||||
validates** the form data into your structure and calls your function.
|
|
||||||
|
|
||||||
File uploads? A breeze with [`TempFile`](@api/rocket/fs/enum.TempFile.html).
|
|
||||||
Bad form request? Rocket doesn’t call your function! Need to know what went
|
|
||||||
wrong? Use a `data` parameter of `Result`! Want to rerender the form with user
|
|
||||||
input and errors? Use [`Context`](guide/requests/#context)!
|
|
||||||
'''
|
|
||||||
|
|
||||||
[[sections]]
|
|
||||||
title = "JSON, always on."
|
|
||||||
code = '''
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
struct Message<'r> {
|
|
||||||
contents: &'r str,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[put("/<id>", data = "<msg>")]
|
|
||||||
fn update(db: &Db, id: Id, msg: Json<Message<'_>>) -> Value {
|
|
||||||
if db.contains_key(&id) {
|
|
||||||
db.insert(id, msg.contents);
|
|
||||||
json!({ "status": "ok" })
|
|
||||||
} else {
|
|
||||||
json!({ "status": "error" })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
text = '''
|
|
||||||
Rocket has first-class support for JSON, right out of the box. Simply derive
|
|
||||||
`Deserialize` or `Serialize` to receive or return JSON, respectively.
|
|
||||||
|
|
||||||
Look familiar? Forms, JSON, and all kinds of body data types work through
|
|
||||||
Rocket’s [`FromData`](@api/rocket/data/trait.FromData.html) trait, Rocket’s
|
|
||||||
approach to deriving types from body data. A `data` route parameter can be
|
|
||||||
_any_ type that implements `FromData`. A value of that type will be
|
|
||||||
deserialized automatically from the incoming request body. You can even
|
|
||||||
implement `FromData` for your own types!
|
|
||||||
'''
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Bottom features: displayed above the footer.
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
[[bottom_features]]
|
|
||||||
title = 'Templating'
|
|
||||||
text = "Rocket makes templating a breeze with built-in templating support."
|
|
||||||
image = 'templating-icon'
|
|
||||||
url = 'guide/responses/#templates'
|
|
||||||
button = 'Learn More'
|
|
||||||
color = 'blue'
|
|
||||||
width = '101px'
|
|
||||||
height = '52px'
|
|
||||||
|
|
||||||
[[bottom_features]]
|
|
||||||
title = 'Cookies'
|
|
||||||
text = "View, add, or remove cookies, with or without encryption, without hassle."
|
|
||||||
image = 'cookies-icon'
|
|
||||||
width = '72px'
|
|
||||||
height = '58px'
|
|
||||||
url = 'guide/requests/#cookies'
|
|
||||||
button = 'Learn More'
|
|
||||||
color = 'fucsia'
|
|
||||||
margin = -6
|
|
||||||
|
|
||||||
[[bottom_features]]
|
|
||||||
title = 'WebSockets + Streams'
|
|
||||||
text = "Create and return potentially infinite async streams of data with ease."
|
|
||||||
image = 'streams-icon'
|
|
||||||
url = 'guide/responses/#async-streams'
|
|
||||||
button = 'Learn More'
|
|
||||||
color = 'red'
|
|
||||||
width = '82px'
|
|
||||||
height = '81px'
|
|
||||||
margin = -29
|
|
||||||
|
|
||||||
[[bottom_features]]
|
|
||||||
title = 'Config Profiles'
|
|
||||||
text = "Configure your application your way for debug, release, or anything else!"
|
|
||||||
image = 'config-icon'
|
|
||||||
url = 'guide/configuration/#profiles'
|
|
||||||
button = 'Learn More'
|
|
||||||
color = 'yellow'
|
|
||||||
width = '57px'
|
|
||||||
height = '57px'
|
|
||||||
margin = -3
|
|
||||||
|
|
||||||
[[bottom_features]]
|
|
||||||
title = 'Type-Checked URIs'
|
|
||||||
text = "Never mistype or forget to update a URI again with Rocket's typed URIs."
|
|
||||||
image = 'pencil-icon'
|
|
||||||
url = 'guide/requests/#private-cookies'
|
|
||||||
button = 'Learn More'
|
|
||||||
color = 'orange'
|
|
||||||
width = '60px'
|
|
||||||
height = '60px'
|
|
||||||
margin = -3
|
|
||||||
|
|
||||||
[[bottom_features]]
|
|
||||||
title = 'Structured Middleware'
|
|
||||||
text = "Fairings are Rocket's simpler approach to structured middleware."
|
|
||||||
image = 'ship-icon'
|
|
||||||
url = 'guide/fairings/#fairings'
|
|
||||||
button = 'Learn More'
|
|
||||||
color = 'green'
|
|
||||||
width = '98px'
|
|
||||||
height = '74px'
|
|
||||||
margin = -20
|
|
||||||
|
|
||||||
[[bottom_features]]
|
|
||||||
title = 'Database Support'
|
|
||||||
text = "Store data with ease with Rocket's built-in ORM agnostic database support."
|
|
||||||
image = 'query-icon'
|
|
||||||
url = 'guide/state/#databases'
|
|
||||||
button = 'Learn More'
|
|
||||||
color = 'pink'
|
|
||||||
width = '73px'
|
|
||||||
height = '57px'
|
|
||||||
margin = -3
|
|
||||||
|
|
||||||
[[bottom_features]]
|
|
||||||
title = 'Testing'
|
|
||||||
text = "Unit and integration test using the comprehensive, built-in testing library."
|
|
||||||
image = 'testing-icon'
|
|
||||||
url = 'guide/testing#testing'
|
|
||||||
button = 'Learn More'
|
|
||||||
color = 'aqua'
|
|
||||||
width = '47px'
|
|
||||||
height = '54px'
|
|
||||||
|
|
||||||
[[bottom_features]]
|
|
||||||
title = 'Community'
|
|
||||||
text = "Join an extensive community of 20,000+ Rocketeers that love Rocket."
|
|
||||||
image = 'globe'
|
|
||||||
url = 'https://github.com/rwf2/Rocket/network/dependents'
|
|
||||||
button = 'See Dependents'
|
|
||||||
color = 'purple'
|
|
||||||
width = '55px'
|
|
||||||
height = '55px'
|
|
||||||
margin = -1
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Panels: displayed in a tabbed arrangement.
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
[[panels]]
|
|
||||||
name = "Routing"
|
|
||||||
checked = true
|
|
||||||
content = '''
|
|
||||||
Rocket's main task is to route incoming requests to the appropriate request
|
|
||||||
handler using your application's declared routes. Routes are declared using
|
|
||||||
Rocket's _route_ attributes. The attribute describes the requests that match the
|
|
||||||
route. The attribute is placed on top of a function that is the request handler
|
|
||||||
for that route.
|
|
||||||
|
|
||||||
As an example, consider the simple route below:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[get("/")]
|
|
||||||
fn index() -> &'static str {
|
|
||||||
"Hello, world!"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This `index` route matches any incoming HTTP `GET` request to `/`, the index.
|
|
||||||
The handler returns a `String`. Rocket automatically converts the string into a
|
|
||||||
well-formed HTTP response that includes the appropriate `Content-Type` and body
|
|
||||||
encoding metadata.
|
|
||||||
'''
|
|
||||||
|
|
||||||
[[panels]]
|
|
||||||
name = "Dynamic Params"
|
|
||||||
content = '''
|
|
||||||
Rocket automatically parses dynamic data in path segments into any desired type.
|
|
||||||
To illustrate, let's use the following route:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[get("/hello/<name>/<age>")]
|
|
||||||
fn hello(name: &str, age: u8) -> String {
|
|
||||||
format!("Hello, {} year old named {}!", age, name)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This `hello` route has two dynamic parameters, identified with angle brackets,
|
|
||||||
declared in the route URI: `<name>` and `<age>`. Rocket maps each parameter to
|
|
||||||
an identically named function argument: `name: &str` and `age: u8`. The dynamic
|
|
||||||
data in the incoming request is parsed automatically into a value of the
|
|
||||||
argument's type. The route is called only when parsing succeeds.
|
|
||||||
|
|
||||||
Parsing is directed by the
|
|
||||||
[`FromParam`](@api/rocket/request/trait.FromParam.html) trait. Rocket implements
|
|
||||||
`FromParam` for many standard types, including both `&str` and `u8`. You can
|
|
||||||
implement it for your own types, too!
|
|
||||||
'''
|
|
||||||
|
|
||||||
[[panels]]
|
|
||||||
name = "Handling Data"
|
|
||||||
content = '''
|
|
||||||
Rocket can automatically parse body data, too!
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[post("/login", data = "<login>")]
|
|
||||||
fn login(login: Form<UserLogin>) -> String {
|
|
||||||
format!("Hello, {}!", login.name)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The dynamic parameter declared in the `data` route attribute parameter again
|
|
||||||
maps to a function argument. Here, `login` maps to `login: Form<UserLogin>`.
|
|
||||||
Parsing is again trait-directed, this time by the
|
|
||||||
[`FromData`](@api/rocket/data/trait.FromData.html) trait.
|
|
||||||
|
|
||||||
The [`Form`](@api/rocket/form/struct.Form.html) type is Rocket's [robust form
|
|
||||||
data parser](@guide/requests/#forms). It automatically parses the request body into the internal type,
|
|
||||||
here `UserLogin`. Other built-in `FromData` types include
|
|
||||||
[`Data`](@api/rocket/struct.Data.html),
|
|
||||||
[`Json`](@api/rocket/serde/json/struct.Json.html), and
|
|
||||||
[`MsgPack`](@api/rocket/serde/msgpack/struct.MsgPack.html). As always, you can
|
|
||||||
implement `FromData` for your own types, too!
|
|
||||||
'''
|
|
||||||
|
|
||||||
[[panels]]
|
|
||||||
name = "Request Guards"
|
|
||||||
content = '''
|
|
||||||
In addition to dynamic path and data parameters, request handlers can also
|
|
||||||
contain a third type of parameter: _request guards_. Request guards aren't
|
|
||||||
declared in the route attribute, and any number of them can appear in the
|
|
||||||
request handler signature.
|
|
||||||
|
|
||||||
Request guards _protect_ the handler from running unless some set of conditions
|
|
||||||
are met by the incoming request metadata. For instance, if you are writing an
|
|
||||||
API that requires sensitive calls to be accompanied by an API key in the request
|
|
||||||
header, Rocket can protect those calls via a custom `ApiKey` request guard:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[get("/sensitive")]
|
|
||||||
fn sensitive(key: ApiKey) { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
`ApiKey` protects the `sensitive` handler from running incorrectly. In order for
|
|
||||||
Rocket to call the `sensitive` handler, the `ApiKey` type needs to be derived
|
|
||||||
through a [`FromRequest`](@api/rocket/request/trait.FromRequest.html)
|
|
||||||
implementation, which in this case, validates the API key header. Request guards
|
|
||||||
are a powerful and unique Rocket concept; they centralize application policy and
|
|
||||||
invariants through types.
|
|
||||||
'''
|
|
||||||
|
|
||||||
[[panels]]
|
|
||||||
name = "Responders"
|
|
||||||
content = '''
|
|
||||||
The return type of a request handler can be any type that implements
|
|
||||||
[`Responder`](@api/rocket/response/trait.Responder.html):
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[get("/")]
|
|
||||||
fn route() -> T { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
Above, T must implement `Responder`. Rocket implements `Responder` for many of
|
|
||||||
the standard library types including `&str`, `String`, `File`, `Option`, and
|
|
||||||
`Result`. Rocket also implements custom responders such as
|
|
||||||
[`Redirect`](@api/rocket/response/struct.Redirect.html),
|
|
||||||
[`Flash`](@api/rocket/response/struct.Flash.html), and
|
|
||||||
[`Template`](@api/rocket_dyn_templates/struct.Template.html).
|
|
||||||
|
|
||||||
The task of a `Responder` is to generate a
|
|
||||||
[`Response`](@api/rocket/response/struct.Response.html), if possible.
|
|
||||||
`Responder`s can fail with a status code. When they do, Rocket calls the
|
|
||||||
corresponding error catcher, a `catch` route, which can be declared as follows:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[catch(404)]
|
|
||||||
fn not_found() -> T { ... }
|
|
||||||
```
|
|
||||||
'''
|
|
||||||
|
|
||||||
[[panels]]
|
|
||||||
name = "Launching"
|
|
||||||
content = '''
|
|
||||||
Finally, we get to launch our application! Rocket begins dispatching requests to
|
|
||||||
routes after they've been _mounted_ and the application has been _launched_.
|
|
||||||
These two steps, usually wrtten in a `rocket` function, look like:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[launch]
|
|
||||||
fn rocket() -> _ {
|
|
||||||
rocket::build().mount("/base", routes![index, another])
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The `mount` call takes a _base_ and a set of routes via the `routes!` macro. The
|
|
||||||
base path (`/base` above) is prepended to the path of every route in the list,
|
|
||||||
effectively namespacing the routes. `#[launch]` creates a `main` function that
|
|
||||||
starts the server. In development, Rocket prints useful information to the
|
|
||||||
console to let you know everything is okay.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
🚀 Rocket has launched from http://127.0.0.1:8000
|
|
||||||
```
|
|
||||||
'''
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
# Sponsors
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
[sponsors.diamond]
|
|
||||||
name = "💎 Diamond"
|
|
||||||
tag = "$500/month"
|
|
||||||
color = "#addcde"
|
|
||||||
height = "110px"
|
|
||||||
|
|
||||||
[[sponsors.diamond.sponsors]]
|
|
||||||
name = "Kindness"
|
|
||||||
url = "https://kindness.ai"
|
|
||||||
img = "kindness.png"
|
|
||||||
blurb = "Supporting customers with Kindness"
|
|
||||||
width = "110px"
|
|
||||||
|
|
||||||
[sponsors.gold]
|
|
||||||
name = "💛 Gold"
|
|
||||||
tag = "$250/month"
|
|
||||||
color = "#fffbba"
|
|
||||||
height = "55px"
|
|
||||||
|
|
||||||
[[sponsors.gold.sponsors]]
|
|
||||||
name = "ohne-makler"
|
|
||||||
url = "https://www.ohne-makler.net/"
|
|
||||||
img = "ohne-makler.svg"
|
|
||||||
width = "173px"
|
|
||||||
|
|
||||||
[[sponsors.gold.sponsors]]
|
|
||||||
name = "RWF2"
|
|
||||||
url = "https://rwf2.org"
|
|
||||||
img = "rwf2.gif"
|
|
||||||
blurb = "Rocket Web Framework Foundation"
|
|
||||||
width = "55px"
|
|
||||||
|
|
||||||
[sponsors.bronze]
|
|
||||||
name = "🤎 Bronze"
|
|
||||||
tag = "$50/month"
|
|
||||||
color = "#c7a483"
|
|
||||||
height = "30px"
|
|
||||||
|
|
||||||
[[sponsors.bronze.sponsors]]
|
|
||||||
name = "1Password"
|
|
||||||
url = "https://1password.com"
|
|
||||||
img = "1password.svg"
|
|
||||||
blurb = "The world’s most-loved password manager"
|
|
||||||
width = "30px"
|
|
|
@ -1,394 +0,0 @@
|
||||||
# Rocket v0.2: Managed State & More
|
|
||||||
|
|
||||||
<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.
|
|
||||||
Much of the development in v0.2 was led by the community, either through reports
|
|
||||||
via the [GitHub issue tracker](https://github.com/rwf2/Rocket/issues)
|
|
||||||
or via direct contributions. In fact, there have been **20 unique contributors**
|
|
||||||
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.
|
|
||||||
|
|
||||||
## About Rocket
|
|
||||||
|
|
||||||
Rocket is a web framework for Rust with a focus on ease of use, expressiveness,
|
|
||||||
and speed. Rocket makes it simple to write fast web applications without
|
|
||||||
sacrificing flexibility or type safety. All with minimal code.
|
|
||||||
|
|
||||||
> Rocket's so simple, you feel like you're doing something wrong. It's like if
|
|
||||||
> you're making fire with rocks and suddenly someone gives you a lighter. Even
|
|
||||||
> though you know the lighter makes fire, and does it even faster and better and
|
|
||||||
> with a simple flick, the rock's still in your brain.
|
|
||||||
>
|
|
||||||
> -- <cite>Artem "impowski" Biryukov, January 17, 2017, on **#rocket**</cite>
|
|
||||||
|
|
||||||
## New Features
|
|
||||||
|
|
||||||
Rocket v0.2 includes several new features that make developing Rocket
|
|
||||||
applications simpler, faster, and safer than ever before.
|
|
||||||
|
|
||||||
### Managed State
|
|
||||||
|
|
||||||
Undoubtedly, the star feature of this release is **managed state**. Managed
|
|
||||||
state allows you to pass state to Rocket prior to launching your application and
|
|
||||||
later retrieve that state from any request handler by simply including the
|
|
||||||
state's type in the function signature. It works in two easy steps:
|
|
||||||
|
|
||||||
1. Call `manage` on the `Rocket` instance corresponding to your application
|
|
||||||
with the initial value of the state.
|
|
||||||
2. Add a `State<T>` type to any request handler, where `T` is the type of the
|
|
||||||
value passed into `manage`.
|
|
||||||
|
|
||||||
Rocket takes care of the rest! `State` works through Rocket's [request
|
|
||||||
guards](@guide-v0.3/requests/#request-guards). You can call `manage` any number
|
|
||||||
of times, as long as each call corresponds to a value of a different type.
|
|
||||||
|
|
||||||
As a simple example, consider the following "hit counter" example application:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
struct HitCount(AtomicUsize);
|
|
||||||
|
|
||||||
#[get("/")]
|
|
||||||
fn index(hit_count: State<HitCount>) -> &'static str {
|
|
||||||
hit_count.0.fetch_add(1, Ordering::Relaxed);
|
|
||||||
"Your visit has been recorded!"
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/count")]
|
|
||||||
fn count(hit_count: State<HitCount>) -> String {
|
|
||||||
hit_count.0.load(Ordering::Relaxed).to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
rocket::ignite()
|
|
||||||
.mount("/", routes![index, count])
|
|
||||||
.manage(HitCount(AtomicUsize::new(0)))
|
|
||||||
.launch()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Visiting `/` will record a visit by incrementing the hit count by 1. Visiting
|
|
||||||
the `/count` path will display the current hit count.
|
|
||||||
|
|
||||||
One concern when using _managed state_ is that you might forget to call `manage`
|
|
||||||
with some state's value before launching your application. Not to worry: Rocket
|
|
||||||
has your back! Let's imagine for a second that we forgot to add the call to
|
|
||||||
`manage` on line 17 in the example above. Here's what the compiler would emit
|
|
||||||
when we compile our buggy application:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
warning: HitCount is not currently being managed by Rocket
|
|
||||||
--> src/main.rs:4:21
|
|
||||||
|
|
|
||||||
4 | fn index(hit_count: State<HitCount>) -> &'static str {
|
|
||||||
| ^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: this State request guard will always fail
|
|
||||||
help: maybe add a call to 'manage' here?
|
|
||||||
--> src/main.rs:15:5
|
|
||||||
|
|
|
||||||
15| rocket::ignite()
|
|
||||||
| ^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
warning: HitCount is not currently being managed by Rocket
|
|
||||||
--> src/main.rs:10:21
|
|
||||||
|
|
|
||||||
10 | fn count(hit_count: State<HitCount>) -> String {
|
|
||||||
| ^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: this State request guard will always fail
|
|
||||||
help: maybe add a call to 'manage' here?
|
|
||||||
--> src/main.rs:15:5
|
|
||||||
|
|
|
||||||
15 | rocket::ignite()
|
|
||||||
| ^^^^^^^^^^^^^^^^
|
|
||||||
```
|
|
||||||
|
|
||||||
You can read more about managed state in the [guide](@guide-v0.3/state/), the
|
|
||||||
API docs for [manage](@api-v0.3/rocket/struct.Rocket.html#method.manage), and the API
|
|
||||||
docs for [State](@api-v0.3/rocket/struct.State.html).
|
|
||||||
|
|
||||||
### Unmounted Routes Lint
|
|
||||||
|
|
||||||
A common mistake that new Rocketeers make is forgetting to
|
|
||||||
[mount](@guide-v0.3/overview/#mounting) declared routes. In Rocket v0.2, Rocket
|
|
||||||
adds a _lint_ that results in a compile-time warning for unmounted routes. As a
|
|
||||||
simple illustration, consider the canonical "Hello, world!" Rocket application
|
|
||||||
below, and note that we've forgotten to mount the `hello` route:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[get("/")]
|
|
||||||
fn hello() -> &'static str {
|
|
||||||
"Hello, world!"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
rocket::ignite().launch();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
When this program is compiled, the compiler emits the following warning:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
warning: the 'hello' route is not mounted
|
|
||||||
--> src/main.rs:2:1
|
|
||||||
|
|
|
||||||
2 | fn hello() -> &'static str {
|
|
||||||
| _^ starting here...
|
|
||||||
3 | | "Hello, world!"
|
|
||||||
4 | | }
|
|
||||||
| |_^ ...ending here
|
|
||||||
|
|
|
||||||
= note: Rocket will not dispatch requests to unmounted routes.
|
|
||||||
help: maybe add a call to 'mount' here?
|
|
||||||
--> src/main.rs:7:5
|
|
||||||
|
|
|
||||||
7 | rocket::ignite().launch();
|
|
||||||
| ^^^^^^^^^^^^^^^^
|
|
||||||
```
|
|
||||||
|
|
||||||
The lint can be disabled selectively per route by adding an
|
|
||||||
`#[allow(unmounted_route)]` annotation to a given route declaration. It can also
|
|
||||||
be disabled globally by adding `#![allow(unmounted_route)]`. You can read more
|
|
||||||
about this lint in the [codegen documentation](@api-v0.3/rocket_codegen/index.html).
|
|
||||||
|
|
||||||
### Configuration via Environment Variables
|
|
||||||
|
|
||||||
A new feature that makes deploying Rocket apps to the cloud a little easier is
|
|
||||||
configuration via environment variables. Simply put, any configuration parameter
|
|
||||||
can be set via an environment variable of the form `ROCKET_{PARAM}`, where
|
|
||||||
`{PARAM}` is the name of the configuration parameter. For example, to set the
|
|
||||||
`port` Rocket listens on, simply set the `ROCKET_PORT` environment variable:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
ROCKET_PORT=3000 cargo run --release
|
|
||||||
```
|
|
||||||
|
|
||||||
Configuration parameters set via environment variables take precedence over
|
|
||||||
parameters set via the `Rocket.toml` configuration file. Note that _any_
|
|
||||||
parameter can be set via an environment variable, include _extras_. For more
|
|
||||||
about configuration in Rocket, see the [configuration section of the
|
|
||||||
guide](@guide-v0.3/configuration).
|
|
||||||
|
|
||||||
### And Plenty More!
|
|
||||||
|
|
||||||
Rocket v0.2 is full of many new features! In addition to the three features
|
|
||||||
described above, v0.2 also includes the following:
|
|
||||||
|
|
||||||
* `Config` structures can be built via `ConfigBuilder`, which follows the
|
|
||||||
builder pattern.
|
|
||||||
* Logging can be enabled or disabled on custom configuration via a second
|
|
||||||
parameter to the `Rocket::custom` method.
|
|
||||||
* `name` and `value` methods were added to `Header` to retrieve the name and
|
|
||||||
value of a header.
|
|
||||||
* A new configuration parameter, `workers`, can be used to set the number of
|
|
||||||
threads Rocket uses.
|
|
||||||
* The address of the remote connection is available via `Request.remote()`.
|
|
||||||
Request preprocessing overrides remote IP with value from the `X-Real-IP`
|
|
||||||
header, if present.
|
|
||||||
* During testing, the remote address can be set via `MockRequest.remote()`.
|
|
||||||
* The `SocketAddr` request guard retrieves the remote address.
|
|
||||||
* A `UUID` type has been added to `contrib`.
|
|
||||||
* `rocket` and `rocket_codegen` will refuse to build with an incompatible
|
|
||||||
nightly version and emit nice error messages.
|
|
||||||
* Major performance and usability improvements were upstreamed to the `cookie`
|
|
||||||
crate, including the addition of a `CookieBuilder`.
|
|
||||||
* When a checkbox isn't present in a form, `bool` types in a `FromForm`
|
|
||||||
structure will parse as `false`.
|
|
||||||
* The `FormItems` iterator can be queried for a complete parse via `completed`
|
|
||||||
and `exhausted`.
|
|
||||||
* Routes for `OPTIONS` requests can be declared via the `options` decorator.
|
|
||||||
* Strings can be percent-encoded via `URI::percent_encode()`.
|
|
||||||
|
|
||||||
## Breaking Changes
|
|
||||||
|
|
||||||
This release includes several breaking changes. These changes are listed below
|
|
||||||
along with a short note about how to handle the breaking change in existing
|
|
||||||
applications.
|
|
||||||
|
|
||||||
* **`Rocket::custom` takes two parameters, the first being `Config` by
|
|
||||||
value.**
|
|
||||||
|
|
||||||
A call in v0.1 of the form `Rocket::custom(&config)` is now
|
|
||||||
`Rocket::custom(config, false)`.
|
|
||||||
|
|
||||||
* **Tera templates are named without their extension.**
|
|
||||||
|
|
||||||
A templated named `name.html.tera` is now simply `name`.
|
|
||||||
|
|
||||||
* **`JSON` `unwrap` method has been renamed to `into_inner`.**
|
|
||||||
|
|
||||||
A call to `.unwrap()` should be changed to `.into_inner()`.
|
|
||||||
|
|
||||||
* **The `map!` macro was removed in favor of the `json!` macro.**
|
|
||||||
|
|
||||||
A call of the form `map!{ "a" => b }` can be written as: `json!({ "a": b
|
|
||||||
})`.
|
|
||||||
|
|
||||||
* **The `hyper::SetCookie` header is no longer exported.**
|
|
||||||
|
|
||||||
Use the `Cookie` type as an `Into<Header>` type directly.
|
|
||||||
|
|
||||||
* **The `Content-Type` for `String` is now `text/plain`.**
|
|
||||||
|
|
||||||
Use `content::HTML<String>` for HTML-based `String` responses.
|
|
||||||
|
|
||||||
* **`Request.content_type()` returns an `Option<ContentType>`.**
|
|
||||||
|
|
||||||
Use `.unwrap_or(ContentType::Any)` to get the old behavior.
|
|
||||||
|
|
||||||
* **The `ContentType` request guard forwards when the request has no
|
|
||||||
`Content-Type` header.**
|
|
||||||
|
|
||||||
Use an `Option<ContentType>` and `.unwrap_or(ContentType::Any)` for the old
|
|
||||||
behavior.
|
|
||||||
|
|
||||||
* **A `Rocket` instance must be declared _before_ a `MockRequest`.**
|
|
||||||
|
|
||||||
Change the order of the `rocket::ignite()` and `MockRequest::new()` calls.
|
|
||||||
|
|
||||||
* **A route with `format` specified only matches requests with the same
|
|
||||||
format.**
|
|
||||||
|
|
||||||
Previously, a route with a `format` would match requests without a format
|
|
||||||
specified. There is no workaround to this change; simply specify formats
|
|
||||||
when required.
|
|
||||||
|
|
||||||
* **`FormItems` can no longer be constructed directly.**
|
|
||||||
|
|
||||||
Instead of constructing as `FormItems(string)`, construct as
|
|
||||||
`FormItems::from(string)`.
|
|
||||||
|
|
||||||
* **`from_from_string(&str)` in `FromForm` removed in favor of
|
|
||||||
`from_form_items(&mut FormItems)`.**
|
|
||||||
|
|
||||||
Most implementation should be using `FormItems` internally; simply use the
|
|
||||||
passed in `FormItems`. In other cases, the form string can be retrieved via
|
|
||||||
the `inner_str` method of `FormItems`.
|
|
||||||
|
|
||||||
* **`Config::{set, default_for}` are deprecated.**
|
|
||||||
|
|
||||||
Use the `set_{param}` methods instead of `set`, and `new` or `build` in
|
|
||||||
place of `default_for`.
|
|
||||||
|
|
||||||
* **Route paths must be absolute.**
|
|
||||||
|
|
||||||
Prepend a `/` to convert a relative path into an absolute one.
|
|
||||||
|
|
||||||
* **Route paths cannot contain empty segments.**
|
|
||||||
|
|
||||||
Remove any empty segments, including trailing ones, from a route path.
|
|
||||||
|
|
||||||
## Bug Fixes
|
|
||||||
|
|
||||||
Three bugs were fixed in this release:
|
|
||||||
|
|
||||||
* Handlebars partials were not properly registered
|
|
||||||
([#122](https://github.com/rwf2/Rocket/issues/122)).
|
|
||||||
* `Rocket::custom` did not set the custom configuration as the `active`
|
|
||||||
configuration.
|
|
||||||
* Route path segments with more than one dynamic parameter were erroneously
|
|
||||||
allowed.
|
|
||||||
|
|
||||||
## General Improvements
|
|
||||||
|
|
||||||
In addition to new features, Rocket saw the following smaller improvements:
|
|
||||||
|
|
||||||
* Rocket no longer overwrites a catcher's response status.
|
|
||||||
* The `port` `Config` type is now a proper `u16`.
|
|
||||||
* Clippy issues injected by codegen are resolved.
|
|
||||||
* Handlebars was updated to `0.25`.
|
|
||||||
* The `PartialEq` implementation of `Config` doesn't consider the path or
|
|
||||||
session key.
|
|
||||||
* Hyper dependency updated to `0.10`.
|
|
||||||
* The `Error` type for `JSON as FromData` has been exposed as `SerdeError`.
|
|
||||||
* SVG was added as a known Content-Type.
|
|
||||||
* Serde was updated to `0.9`.
|
|
||||||
* Form parse failure now results in a **422** error code.
|
|
||||||
* Tera has been updated to `0.7`.
|
|
||||||
* `pub(crate)` is used throughout to enforce visibility rules.
|
|
||||||
* Query parameters in routes (`/path?<param>`) are now logged.
|
|
||||||
* Routes with and without query parameters no longer _collide_.
|
|
||||||
|
|
||||||
Rocket v0.2 also includes all of the new features, bug fixes, and improvements
|
|
||||||
from versions 0.1.1 through 0.1.6. You can read more about these changes in the
|
|
||||||
[v0.1
|
|
||||||
CHANGELOG](https://github.com/rwf2/Rocket/blob/v0.1/CHANGELOG.md).
|
|
||||||
|
|
||||||
## What's next?
|
|
||||||
|
|
||||||
Work now begins on Rocket v0.3! The focus of the next major release will be on
|
|
||||||
security. In particular, three major security features are planned:
|
|
||||||
|
|
||||||
1. **Automatic CSRF protection across all payload-based requests
|
|
||||||
([#14](https://github.com/rwf2/Rocket/issues/14)).**
|
|
||||||
|
|
||||||
Rocket will automatically check the origin of requests made for HTTP `PUT`,
|
|
||||||
`POST`, `DELETE`, and `PATCH` requests, allowing only authorized requests to
|
|
||||||
be dispatched. This includes checking `POST`s from form submissions and any
|
|
||||||
requests made via JavaScript.
|
|
||||||
|
|
||||||
2. **Encryption and signing of session-based cookies
|
|
||||||
([#20](https://github.com/rwf2/Rocket/issues/20)).**
|
|
||||||
|
|
||||||
Built-in session support will encrypt and sign cookies using a user supplied
|
|
||||||
`session_key`. Encryption and signing will occur automatically for
|
|
||||||
session-based cookies.
|
|
||||||
|
|
||||||
3. **Explicit typing of raw HTTP data strings
|
|
||||||
([#43](https://github.com/rwf2/Rocket/issues/43)).**
|
|
||||||
|
|
||||||
A present, the standard `&str` type is used to represent raw HTTP data
|
|
||||||
strings. In the next release, a new type, `&RawStr`, will be used for this
|
|
||||||
purpose. This will make it clear when raw data is being handled. The type
|
|
||||||
will expose convenient methods such as `.url_decode()` and `.html_escape()`.
|
|
||||||
|
|
||||||
Work on Rocket v0.3 will also involve exploring built-in support for user
|
|
||||||
authentication and authorization as well as automatic parsing of multipart
|
|
||||||
forms.
|
|
||||||
|
|
||||||
## Contributors to v0.2
|
|
||||||
|
|
||||||
The following wonderful people helped make Rocket v0.2 happen:
|
|
||||||
|
|
||||||
<ul class="columns">
|
|
||||||
<li>Cliff H</li>
|
|
||||||
<li>Dru Sellers</li>
|
|
||||||
<li>Eijebong</li>
|
|
||||||
<li>Eric D. Reichert</li>
|
|
||||||
<li>Ernestas Poskus</li>
|
|
||||||
<li>FliegendeWurst</li>
|
|
||||||
<li>Garrett Squire</li>
|
|
||||||
<li>Giovanni Capuano</li>
|
|
||||||
<li>Greg Edwards</li>
|
|
||||||
<li>Joel Roller</li>
|
|
||||||
<li>Josh Holmer</li>
|
|
||||||
<li>Liigo Zhuang</li>
|
|
||||||
<li>Lori Holden</li>
|
|
||||||
<li>Marcus Ball</li>
|
|
||||||
<li>Matt McCoy</li>
|
|
||||||
<li>Reilly Tucker Siemens</li>
|
|
||||||
<li>Robert Balicki</li>
|
|
||||||
<li>Sean Griffin</li>
|
|
||||||
<li>Seth Lopez</li>
|
|
||||||
<li>tborsa</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Thank you all! Your contributions are greatly appreciated!
|
|
||||||
|
|
||||||
Looking to help with Rocket's development? Head over to [Rocket's
|
|
||||||
GitHub](https://github.com/rwf2/Rocket#contributing) and start
|
|
||||||
contributing!
|
|
||||||
|
|
||||||
## Start using Rocket today!
|
|
||||||
|
|
||||||
Not already using Rocket? Rocket is extensively documented, making it easy for
|
|
||||||
you to start writing your web applications in Rocket! See the
|
|
||||||
[overview](../../overview) or start writing code immediately by reading through
|
|
||||||
[the guide](@guide-v0.3).
|
|
|
@ -1,331 +0,0 @@
|
||||||
# Rocket v0.3: Fairings, TLS, Private Cookies
|
|
||||||
|
|
||||||
<p class="metadata"><strong>
|
|
||||||
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on July 14, 2017
|
|
||||||
</strong></p>
|
|
||||||
|
|
||||||
I'm excited to announce that the next major release of Rocket is available
|
|
||||||
today! Rocket 0.3 is packed with new features and improvements that increase
|
|
||||||
developer productivity, improve application security, and provide new
|
|
||||||
opportunities for extensibility. Rocket 0.3 is the culmination of almost 6
|
|
||||||
months of work. During this time, more than 225 changes were committed, over 100
|
|
||||||
issues (primarily questions and feature requests) were closed, and over 40 pull
|
|
||||||
requests were submitted. The Rocket community has proven steadfast in their
|
|
||||||
support: a sincere thank you to everyone involved!
|
|
||||||
|
|
||||||
## About Rocket
|
|
||||||
|
|
||||||
Rocket is a web framework for Rust with a focus on ease of use, expressiveness,
|
|
||||||
and speed. Rocket makes it simple to write fast web applications without
|
|
||||||
sacrificing flexibility or type safety. All with minimal code.
|
|
||||||
|
|
||||||
Not already using Rocket? Join the thousands of users and dozens of companies
|
|
||||||
happily using Rocket today! Rocket's extensive documentation makes it easy. Get
|
|
||||||
started now by [reading through the guide](@guide-v0.3) or learning more from
|
|
||||||
[the overview](../../overview).
|
|
||||||
|
|
||||||
## What's New?
|
|
||||||
|
|
||||||
Rocket 0.3 is a _big_ release, packed with over 100 changes. We highlight the
|
|
||||||
biggest new features here. For a complete description of everything new and
|
|
||||||
different in 0.3, please see the [CHANGELOG].
|
|
||||||
|
|
||||||
[CHANGELOG]: https://github.com/rwf2/Rocket/blob/v0.3.0/CHANGELOG.md#version-030-jul-14-2017
|
|
||||||
|
|
||||||
### Fairings
|
|
||||||
|
|
||||||
Fairings bring structured middleware to Rocket. With fairings, Rocket
|
|
||||||
applications can hook into the application lifecycle to record or rewrite
|
|
||||||
information about incoming requests, outgoing responses, and the Rocket
|
|
||||||
application itself.
|
|
||||||
|
|
||||||
Rocket's fairings are a lot like middleware from other frameworks, but they bear
|
|
||||||
a few key distinctions:
|
|
||||||
|
|
||||||
* Fairings cannot directly terminate or respond to an incoming request.
|
|
||||||
* Fairings cannot inject arbitrary, non-request data into a request.
|
|
||||||
* Fairings _can_ prevent an application from launching.
|
|
||||||
* Fairings _can_ inspect and modify the application's configuration.
|
|
||||||
|
|
||||||
Fairings are implemented through Rocket's [`Fairing`] trait. The trait consists
|
|
||||||
of callback methods that Rocket invokes as needed. A fairing can subscribe to
|
|
||||||
receive callbacks for the following four events:
|
|
||||||
|
|
||||||
* **Attach**: called when a fairing is first registered.
|
|
||||||
* **Launch**: called immediately before the Rocket application launches.
|
|
||||||
* **Request**: called just after a request is received.
|
|
||||||
* **Response**: called when a response is ready to be returned.
|
|
||||||
|
|
||||||
The new [fairings guide] describes fairings in detail, expands on their
|
|
||||||
limitations and abilities, and includes implementation examples. I encourage you
|
|
||||||
to experiment with fairings and report your experiences. As always, feedback is
|
|
||||||
instrumental in solidifying a robust design.
|
|
||||||
|
|
||||||
[`Fairing`]: @api-v0.3/rocket/fairing/trait.Fairing.html
|
|
||||||
[fairings guide]: @guide-v0.3/fairings
|
|
||||||
|
|
||||||
### Native TLS Support
|
|
||||||
|
|
||||||
Rocket 0.3 includes built-in, experimental support for TLS, powered by
|
|
||||||
[`rustls`]. To enable TLS support, compile Rocket with the `tls` feature
|
|
||||||
enabled. Then, configure file paths to an RSA certificate chain and
|
|
||||||
corresponding private key in the `Rocket.toml` file or via environment
|
|
||||||
variables:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[global.tls]
|
|
||||||
certs = "/path/to/certs.pem"
|
|
||||||
key = "/path/to/key.pem"
|
|
||||||
```
|
|
||||||
|
|
||||||
TLS support in Rocket is experimental and not yet recommended for general use
|
|
||||||
over the internet. Instead, prefer to place Rocket behind a mature reverse-proxy
|
|
||||||
such as NGINX. That being said, use of Rocket's TLS support is encouraged for
|
|
||||||
local networking (such as local-only IoT devices) or as required during
|
|
||||||
development.
|
|
||||||
|
|
||||||
For more details on Rocket's TLS support, see the [configuring TLS] section of
|
|
||||||
the guide.
|
|
||||||
|
|
||||||
[`rustls`]: https://github.com/ctz/rustls
|
|
||||||
[configuring TLS]: @guide-v0.3/configuration/#configuring-tls
|
|
||||||
|
|
||||||
### Private Cookies
|
|
||||||
|
|
||||||
In Rocket 0.3, cookies can be _private_. Private cookies 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.
|
|
||||||
|
|
||||||
Retrieving, adding, and removing private cookies is done via the new
|
|
||||||
[`get_private`], [`add_private`], and [`remove_private`] methods on the
|
|
||||||
[`Cookies`] type. As an example, consider the code below which sets and
|
|
||||||
retrieves a `user_id` private cookie in two routes:
|
|
||||||
|
|
||||||
```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("/"), "Successfully logged out.")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To encrypt private cookies, Rocket uses the 256-bit key specified in the
|
|
||||||
`secret_key` configuration parameter. If one is not specified, Rocket
|
|
||||||
automatically generates a fresh key at launch.
|
|
||||||
|
|
||||||
For more details on private cookies, see the [private cookies] section of the
|
|
||||||
guide.
|
|
||||||
|
|
||||||
[`Cookies`]: @api-v0.3/rocket/http/enum.Cookies.html
|
|
||||||
[`get_private`]: @api-v0.3/rocket/http/enum.Cookies.html#method.get_private
|
|
||||||
[`add_private`]: @api-v0.3/rocket/http/enum.Cookies.html#method.add_private
|
|
||||||
[`remove_private`]: @api-v0.3/rocket/http/enum.Cookies.html#method.remove_private
|
|
||||||
[private cookies]: @guide-v0.3/requests/#private-cookies
|
|
||||||
|
|
||||||
### Form Field Naming
|
|
||||||
|
|
||||||
In 0.2 and below, Rocket always matches form field names to structure field
|
|
||||||
names exactly when deriving [`FromForm`]. This presented an issue when an
|
|
||||||
invalid Rust identifier was used as a form field's name. For example, it was not
|
|
||||||
possible to represent a form with a field name of "type" since `type` is a
|
|
||||||
keyword and thus an illegal identifier. The following resulted in a compile-time
|
|
||||||
error:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[derive(FromForm)]
|
|
||||||
struct External {
|
|
||||||
type: String
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In Rocket 0.3, you can ask Rocket to match against a different form field for a
|
|
||||||
given structure field by using the `#[form(field = "name")]` field annotation.
|
|
||||||
As a result, the "type" form field can now be captured using something like the
|
|
||||||
following:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[derive(FromForm)]
|
|
||||||
struct External {
|
|
||||||
#[form(field = "type")]
|
|
||||||
api_type: String
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Rocket will automatically match the form field named "type" to the structure
|
|
||||||
field named `api_type`. For more details on form field naming, see the [field
|
|
||||||
renaming](@guide-v0.3/requests/#field-renaming) section of the guide.
|
|
||||||
|
|
||||||
[`FromForm`]: @api-v0.3/rocket/request/trait.FromForm.html
|
|
||||||
|
|
||||||
### And Plenty More!
|
|
||||||
|
|
||||||
In addition to the four highlighted above, Rocket 0.3 also ships with the
|
|
||||||
following new features:
|
|
||||||
|
|
||||||
* A [`MsgPack`] type has been added for simple consumption and returning of
|
|
||||||
MessagePack data.
|
|
||||||
* [`Rocket::launch()`] returns launch failures ([`LaunchError`]) for
|
|
||||||
inspection without panicking.
|
|
||||||
* Routes without query parameters now match requests with or without query
|
|
||||||
parameters.
|
|
||||||
* [Default rankings] prefer static paths and routes with query string matches.
|
|
||||||
* A native [`Accept`] header structure was added.
|
|
||||||
* The [`Accept`] request header can be retrieved via [`Request::accept()`].
|
|
||||||
* All active routes can be retrieved via [`Rocket::routes()`].
|
|
||||||
* [`Response::body_string()`] was added to retrieve the response body as a
|
|
||||||
`String`.
|
|
||||||
* [`Response::body_bytes()`] was added to retrieve the response body as a
|
|
||||||
`Vec<u8>`.
|
|
||||||
* [`Response::content_type()`] was added to retrieve the Content-Type header
|
|
||||||
of a response.
|
|
||||||
* Data limits on incoming data are [now
|
|
||||||
configurable](@guide-v0.3/configuration/#data-limits).
|
|
||||||
* [`Request::limits()`] was added to retrieve incoming data limits.
|
|
||||||
* Responders may dynamically adjust their response based on the incoming
|
|
||||||
request.
|
|
||||||
* [`Request::guard()`] was added for simple retrieval of request guards.
|
|
||||||
* [`Request::route()`] was added to retrieve the active route, if any.
|
|
||||||
* [`&Route`] is now a request guard.
|
|
||||||
* The base mount path of a [`Route`] can be retrieved via `Route::base` or
|
|
||||||
`Route::base()`.
|
|
||||||
* `Config::{development, staging, production}` constructors were added for
|
|
||||||
[`Config`].
|
|
||||||
* [`Config::get_datetime()`] was added to retrieve an extra as a `Datetime`.
|
|
||||||
* Forms can be now parsed _leniently_ via the new [`LenientForm`] data guard.
|
|
||||||
* The `?` operator can now be used with `Outcome`.
|
|
||||||
* Quoted string, array, and table [configuration parameters] can be set via
|
|
||||||
environment variables.
|
|
||||||
* Log coloring is disabled when `stdout` is not a TTY.
|
|
||||||
* [`FromForm`] is implemented for `Option<T: FromForm>`, `Result<T: FromForm,
|
|
||||||
T::Error>`.
|
|
||||||
* The [`NotFound`] responder was added for simple **404** response
|
|
||||||
construction.
|
|
||||||
|
|
||||||
[`MsgPack`]: @api-v0.3/rocket_contrib/msgpack/struct.MsgPack.html
|
|
||||||
[`Rocket::launch()`]: @api-v0.3/rocket/struct.Rocket.html#method.launch
|
|
||||||
[`LaunchError`]: @api-v0.3/rocket/error/struct.LaunchError.html
|
|
||||||
[Default rankings]: @api-v0.3/rocket/struct.Route.html
|
|
||||||
[`&Route`]: @api-v0.3/rocket/struct.Route.html
|
|
||||||
[`Route`]: @api-v0.3/rocket/struct.Route.html
|
|
||||||
[`Accept`]: @api-v0.3/rocket/http/struct.Accept.html
|
|
||||||
[`Request::accept()`]: @api-v0.3/rocket/struct.Request.html#method.accept
|
|
||||||
[`contrib`]: @api-v0.3/rocket_contrib/
|
|
||||||
[`Rocket::routes()`]: @api-v0.3/rocket/struct.Rocket.html#method.routes
|
|
||||||
[`Response::body_string()`]: @api-v0.3/rocket/struct.Response.html#method.body_string
|
|
||||||
[`Response::body_bytes()`]: @api-v0.3/rocket/struct.Response.html#method.body_bytes
|
|
||||||
[`Response::content_type()`]: @api-v0.3/rocket/struct.Response.html#method.content_type
|
|
||||||
[`Request::guard()`]: @api-v0.3/rocket/struct.Request.html#method.guard
|
|
||||||
[`Request::limits()`]: @api-v0.3/rocket/struct.Request.html#method.limits
|
|
||||||
[`Request::route()`]: @api-v0.3/rocket/struct.Request.html#method.route
|
|
||||||
[`Config`]: @api-v0.3/rocket/struct.Config.html
|
|
||||||
[`Cookies`]: @api-v0.3/rocket/http/enum.Cookies.html
|
|
||||||
[`Config::get_datetime()`]: @api-v0.3/rocket/struct.Config.html#method.get_datetime
|
|
||||||
[`LenientForm`]: @api-v0.3/rocket/request/struct.LenientForm.html
|
|
||||||
[configuration parameters]: @api-v0.3/rocket/config/index.html#environment-variables
|
|
||||||
[`NotFound`]: @api-v0.3/rocket/response/status/struct.NotFound.html
|
|
||||||
|
|
||||||
## Breaking Changes
|
|
||||||
|
|
||||||
This release includes many breaking changes such as support for `serde` 1.0. To
|
|
||||||
keep this release note short, please see the
|
|
||||||
[CHANGELOG](https://github.com/rwf2/Rocket/blob/v0.3.0/CHANGELOG.md#breaking-changes)
|
|
||||||
for the full list of breaking changes along with a short note about how to
|
|
||||||
handle the breaking change in existing applications.
|
|
||||||
|
|
||||||
## General Improvements
|
|
||||||
|
|
||||||
In addition to new features, Rocket saw the following improvements:
|
|
||||||
|
|
||||||
* "Rocket" is now capitalized in the `Server` HTTP header.
|
|
||||||
* The generic parameter of `rocket_contrib::Json` defaults to `json::Value`.
|
|
||||||
* The trailing '...' in the launch message was removed.
|
|
||||||
* The launch message prints regardless of the config environment.
|
|
||||||
* For debugging, `FromData` is implemented for `Vec<u8>` and `String`.
|
|
||||||
* The port displayed on launch is the port resolved, not the one configured.
|
|
||||||
* The `uuid` dependency was updated to `0.5`.
|
|
||||||
* The `base64` dependency was updated to `0.6`.
|
|
||||||
* The `toml` dependency was updated to `0.4`.
|
|
||||||
* The `handlebars` dependency was updated to `0.27`.
|
|
||||||
* The `tera` dependency was updated to `0.10`.
|
|
||||||
* [`yansi`] is now used for all terminal coloring.
|
|
||||||
* The `dev` `rustc` release channel is supported during builds.
|
|
||||||
* [`Config`] is now exported from the root.
|
|
||||||
* [`Request`] implements `Clone` and `Debug`.
|
|
||||||
* The `workers` config parameter now defaults to `num_cpus * 2`.
|
|
||||||
* Console logging for table-based config values is improved.
|
|
||||||
* `PartialOrd`, `Ord`, and `Hash` are now implemented for [`State`].
|
|
||||||
* The format of a request is always logged when available.
|
|
||||||
|
|
||||||
[`yansi`]: https://crates.io/crates/yansi
|
|
||||||
[`Request`]: @api-v0.3/rocket/struct.Request.html
|
|
||||||
[`State`]: @api-v0.3/rocket/struct.State.html
|
|
||||||
[`Config`]: @api-v0.3/rocket/struct.Config.html
|
|
||||||
|
|
||||||
## What's Next?
|
|
||||||
|
|
||||||
Rocket 0.4, of course! The focus of the next major release is two-fold: security
|
|
||||||
and usability. The following major features are planned:
|
|
||||||
|
|
||||||
1. **Automatic CSRF protection across all payload-based requests
|
|
||||||
([#14](https://github.com/rwf2/Rocket/issues/14)).**
|
|
||||||
|
|
||||||
This is a carry-over from the 0.3 wishlist. Rocket will automatically check
|
|
||||||
the origin of requests made for HTTP `PUT`, `POST`, `DELETE`, and `PATCH`
|
|
||||||
requests, allowing only valid requests to be dispatched. This includes
|
|
||||||
checking form submissions and requests made via JavaScript.
|
|
||||||
|
|
||||||
2. **First-class database support
|
|
||||||
([#167](https://github.com/rwf2/Rocket/issues/167)).**
|
|
||||||
|
|
||||||
Connecting a database to Rocket is presently [much wordier than necessary].
|
|
||||||
The plan for 0.4 is to minimize the amount of effort. At most, a couple of
|
|
||||||
lines of configuration and a single line of initialization code should be
|
|
||||||
required.
|
|
||||||
|
|
||||||
3. **Typed URL generation from routes
|
|
||||||
([#263](https://github.com/rwf2/Rocket/issues/263)).**
|
|
||||||
|
|
||||||
Explicitly writing URLs is error-prone. Because routes are fully-typed in
|
|
||||||
Rocket, it's possible to check that a URL corresponding to a route
|
|
||||||
type-checks. In the next release, a `url!` macro will be available to
|
|
||||||
automatically generate URLs for routes in a type-safe manner.
|
|
||||||
|
|
||||||
[much wordier than necessary]: @guide-v0.3/state/#databases
|
|
||||||
|
|
||||||
## Contributors to v0.3
|
|
||||||
|
|
||||||
The following wonderful people helped make Rocket v0.3 happen:
|
|
||||||
|
|
||||||
<ul class="columns">
|
|
||||||
<li>Alan Stoate</li>
|
|
||||||
<li>Alexey Zabelin</li>
|
|
||||||
<li>Anton Pirker</li>
|
|
||||||
<li>Fabrice Desré</li>
|
|
||||||
<li>Ivar Abrahamsen</li>
|
|
||||||
<li>Josh Holmer</li>
|
|
||||||
<li>Joshua Rombauer</li>
|
|
||||||
<li>Lance Carlson</li>
|
|
||||||
<li>Lori Holden</li>
|
|
||||||
<li>Roman Frołow</li>
|
|
||||||
<li>Ryan Leckey</li>
|
|
||||||
<li>Stephan Buys</li>
|
|
||||||
<li>Tomek Wałkuski</li>
|
|
||||||
<li>Vesa Kaihlavirta</li>
|
|
||||||
<li>Yong Wen Chua</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Thank you all! Your contributions are greatly appreciated!
|
|
||||||
|
|
||||||
Looking to help with Rocket's development? Head over to [Rocket's
|
|
||||||
GitHub](https://github.com/rwf2/Rocket#contributing) and start
|
|
||||||
contributing!
|
|
|
@ -1,41 +0,0 @@
|
||||||
# Rocket v0.4 Release Candidate
|
|
||||||
|
|
||||||
<p class="metadata"><strong>
|
|
||||||
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on October 31, 2018
|
|
||||||
</strong></p>
|
|
||||||
|
|
||||||
I am delighted to announce that a release candidate for Rocket v0.4 is available
|
|
||||||
today! This release brings over a year of features, improvements, and
|
|
||||||
refinements, resolving some of the most called for requests and bringing Rocket
|
|
||||||
measurably closer to stable compatibility.
|
|
||||||
|
|
||||||
The release candidate is an opportunity to discover issues with Rocket v0.4 and
|
|
||||||
its documentation before its general release. We encourage all users to migrate
|
|
||||||
their applications to the release candidate and report any issues to the [GitHub
|
|
||||||
issue tracker].
|
|
||||||
|
|
||||||
Barring any major issues, the general release of Rocket v0.4 is planned for
|
|
||||||
Friday, November 9th, when we'll post a full news article covering the biggest
|
|
||||||
features and changes in Rocket v0.4. Until then, the [CHANGELOG] contains every
|
|
||||||
feature addition, change, and improvement since v0.3, as well as information on
|
|
||||||
migrating your applications to v0.4. All documentation, including the [guide]
|
|
||||||
and [API docs], has been updated in full for v0.4.
|
|
||||||
|
|
||||||
We're excited for your feedback, and we look forward to seeing you again on
|
|
||||||
Friday, November 9th for the general release!
|
|
||||||
|
|
||||||
[GitHub issue tracker]: https://github.com/rwf2/Rocket/issues
|
|
||||||
[API docs]: https://api.rocket.rs/v0.4/rocket/
|
|
||||||
[guide]: @guide-v0.4
|
|
||||||
[CHANGELOG]: https://github.com/rwf2/Rocket/tree/v0.4/CHANGELOG.md#version-040-rc-oct-31-2018
|
|
||||||
|
|
||||||
## About Rocket
|
|
||||||
|
|
||||||
Rocket is a web framework for Rust with a focus on ease of use, expressiveness,
|
|
||||||
and speed. Rocket makes it simple to write fast web applications without
|
|
||||||
sacrificing flexibility or type safety. All with minimal code.
|
|
||||||
|
|
||||||
Not already using Rocket? Join the tens of thousands of users and hundreds of
|
|
||||||
companies happily using Rocket today! Rocket's extensive documentation makes it
|
|
||||||
easy. Get started now by [reading through the guide](@guide-v0.4) or learning
|
|
||||||
more from [the overview](../../overview).
|
|
|
@ -1,48 +0,0 @@
|
||||||
# Rocket's 2nd v0.4 Release Candidate
|
|
||||||
|
|
||||||
<p class="metadata"><strong>
|
|
||||||
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on November 30, 2018
|
|
||||||
</strong></p>
|
|
||||||
|
|
||||||
After a successful and productive initial v0.4 release candidate, I am happy to
|
|
||||||
announce that the second release candidate for Rocket v0.4 is now available.
|
|
||||||
|
|
||||||
This release candidate fixes issues identified during the first release
|
|
||||||
candidate, introduces further features, and leverages upstream `rustc`
|
|
||||||
contributions for improved diagnostics and stability. As before, this is an
|
|
||||||
opportunity to discover issues with Rocket v0.4 and its documentation before its
|
|
||||||
general release. We encourage all users to migrate their applications to the
|
|
||||||
second release candidate and report any issues to the [GitHub issue tracker].
|
|
||||||
To update to `v0.4.0`, manually update `rocket` in your `Cargo.toml` file:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
rocket = "0.4.0"
|
|
||||||
```
|
|
||||||
|
|
||||||
Barring any major issues, of which none are expected, the general release of
|
|
||||||
Rocket v0.4 is planned for Wednesday, December 5th, when we'll post a full news
|
|
||||||
article covering the biggest features and changes in Rocket v0.4. Until then,
|
|
||||||
the [CHANGELOG] contains every feature addition, change, and improvement since
|
|
||||||
v0.4.0-rc.1 and v0.3, as well as information on migrating your applications to
|
|
||||||
v0.4. All documentation, including the [guide] and [API docs], has been updated
|
|
||||||
in full for the second release candidate.
|
|
||||||
|
|
||||||
We're excited for your feedback, and we look forward to seeing you again on
|
|
||||||
Wednesday, December 5th for the general release!
|
|
||||||
|
|
||||||
[GitHub issue tracker]: https://github.com/rwf2/Rocket/issues
|
|
||||||
[API docs]: @api-v0.4
|
|
||||||
[guide]: @guide-v0.4
|
|
||||||
[CHANGELOG]: https://github.com/rwf2/Rocket/tree/v0.4/CHANGELOG.md#version-040-rc2-nov-30-2018
|
|
||||||
|
|
||||||
## About Rocket
|
|
||||||
|
|
||||||
Rocket is a web framework for Rust with a focus on ease of use, expressiveness,
|
|
||||||
and speed. Rocket makes it simple to write fast web applications without
|
|
||||||
sacrificing flexibility or type safety. All with minimal code.
|
|
||||||
|
|
||||||
Not already using Rocket? Join the tens of thousands of users and hundreds of
|
|
||||||
companies happily using Rocket today! Rocket's extensive documentation makes it
|
|
||||||
easy. Get started now by [reading through the guide](@guide-v0.4) or learning
|
|
||||||
more from [the overview](../../overview).
|
|
|
@ -1,574 +0,0 @@
|
||||||
# Rocket v0.4: Typed URIs, Database Support, Revamped Queries, & More!
|
|
||||||
|
|
||||||
<p class="metadata"><strong>
|
|
||||||
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on December 08, 2018
|
|
||||||
</strong></p>
|
|
||||||
|
|
||||||
I am elated to announce that the next major release of Rocket is now available!
|
|
||||||
Rocket 0.4 is a step forward in every direction: it is **packed** with features
|
|
||||||
and improvements that increase developer productivity, improve application
|
|
||||||
security and robustness, provide new opportunities for extensibility, and
|
|
||||||
deliver a renewed degree of toolchain stability.
|
|
||||||
|
|
||||||
Rocket 0.4 is the culmination of more than a year of development. During this
|
|
||||||
time, more than 600 changes were committed, almost 400 issues were closed, and
|
|
||||||
over 165 pull requests were submitted. The Rocket community has proved steadfast
|
|
||||||
in its support: a sincere thank you to everyone involved!
|
|
||||||
|
|
||||||
## About Rocket
|
|
||||||
|
|
||||||
Rocket is a web framework for Rust with a focus on usability, security, and
|
|
||||||
performance. Rocket makes it simple to write fast, secure web applications
|
|
||||||
without sacrificing flexibility or type safety.
|
|
||||||
|
|
||||||
Not already using Rocket? Join the tens of thousands of users and hundreds of
|
|
||||||
companies happily using Rocket today! Rocket's extensive documentation makes it
|
|
||||||
easy. Get started now by [reading through the guide](@guide-v0.4) or learning
|
|
||||||
more from [the overview](../../overview).
|
|
||||||
|
|
||||||
## What's New?
|
|
||||||
|
|
||||||
Rocket 0.4 is the largest release to date by a _wide_ margin. It is packed with
|
|
||||||
hundreds of changes. We highlight the largest of them here. For a complete
|
|
||||||
description of everything new and different in 0.4, please see the [CHANGELOG].
|
|
||||||
|
|
||||||
[CHANGELOG]: https://github.com/rwf2/Rocket/blob/v0.4.0/CHANGELOG.md#version-040-dec-06-2018
|
|
||||||
|
|
||||||
### Maintainers += 1
|
|
||||||
|
|
||||||
An open source project is as much about the people as it is about the code. This
|
|
||||||
is why I am delighted to welcome [@jebrosen] as Rocket's first co-maintainer!
|
|
||||||
Jeb is directly responsible for several of the new features in 0.4, has
|
|
||||||
painstakingly code reviewed many other changes, and actively answers questions
|
|
||||||
and resolves issues on GitHub, IRC, and offline.
|
|
||||||
|
|
||||||
Needless to say, Rocket is a better project thanks to you, Jeb. Welcome!
|
|
||||||
|
|
||||||
[@jebrosen]: https://github.com/jebrosen
|
|
||||||
|
|
||||||
### Codegen Rewrite
|
|
||||||
|
|
||||||
In 0.4, the [`rocket_codegen`] crate has been entirely rewritten to use
|
|
||||||
to-be-stable procedural macro APIs where it previously used private, unstable
|
|
||||||
`rustc` APIs. While this is largely an internal change, it has big, positive
|
|
||||||
implications for all Rocket users.
|
|
||||||
|
|
||||||
First and foremost, the path to Rocket on stable is now clearly in sight. While
|
|
||||||
there are still hurdles to overcome, we are actively working with the Rust team
|
|
||||||
to make Rocket on stable a reality as soon as possible. We expect the next major
|
|
||||||
Rocket release to support the stable channel.
|
|
||||||
|
|
||||||
Second, but equally important, we expect breakages due to nightly changes to
|
|
||||||
drop dramatically, likely to zero. This means that Rocket is largely already
|
|
||||||
_de-facto_ toolchain stable.
|
|
||||||
|
|
||||||
The new prelude import for Rocket applications is:
|
|
||||||
|
|
||||||
```diff
|
|
||||||
- #![feature(plugin)]
|
|
||||||
- #![plugin(rocket_codegen)]
|
|
||||||
+ #![feature(proc_macro_hygiene, decl_macro)]
|
|
||||||
|
|
||||||
- extern crate rocket;
|
|
||||||
+ #[macro_use] extern crate rocket;
|
|
||||||
```
|
|
||||||
|
|
||||||
[`rocket_codegen`] should **_not_** be a direct dependency. Remove it from your
|
|
||||||
`Cargo.toml`:
|
|
||||||
|
|
||||||
```diff
|
|
||||||
[dependencies]
|
|
||||||
- rocket = "0.3"
|
|
||||||
+ rocket = "0.4"
|
|
||||||
- rocket_codegen = "0.3"
|
|
||||||
```
|
|
||||||
|
|
||||||
[`rocket_codegen`]: https://api.rocket.rs/v0.4/rocket_codegen/index.html
|
|
||||||
|
|
||||||
### Typed URIs
|
|
||||||
|
|
||||||
Rocket 0.4 introduces the [`uri!`] macro, allowing you to construct URIs to
|
|
||||||
routes in a robust, type-safe, and URI-safe manner. Type or route parameter
|
|
||||||
mismatches are caught at compile-time, and changes to route URIs are
|
|
||||||
automatically reflected in the generated URIs.
|
|
||||||
|
|
||||||
To illustrate, consider the following route:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[get("/person/<name>?<age>")]
|
|
||||||
fn person(name: String, age: Option<u8>)
|
|
||||||
```
|
|
||||||
|
|
||||||
URIs to this `person` route can be created as follows:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
// with unnamed parameters, in route URI declaration order
|
|
||||||
let uri = uri!(person: "Mike Smith", 28);
|
|
||||||
assert_eq!(uri.to_string(), "/person/Mike%20Smith?age=28");
|
|
||||||
|
|
||||||
// with named parameters, order irrelevant
|
|
||||||
let uri = uri!(person: name = "Mike", age = 28);
|
|
||||||
let uri = uri!(person: age = 28, name = "Mike");
|
|
||||||
assert_eq!(uri.to_string(), "/person/Mike?age=28");
|
|
||||||
|
|
||||||
// with a specific mount-point
|
|
||||||
let uri = uri!("/api", person: name = "Mike", age = 28);
|
|
||||||
assert_eq!(uri.to_string(), "/api/person/Mike?age=28");
|
|
||||||
|
|
||||||
// with optional query parameters ignored
|
|
||||||
let uri = uri!(person: "Mike", _);
|
|
||||||
let uri = uri!(person: name = "Mike", age = _);
|
|
||||||
assert_eq!(uri.to_string(), "/person/Mike");
|
|
||||||
```
|
|
||||||
|
|
||||||
Should your route's URI change in an incompatible manner, or should you mistype
|
|
||||||
parameters, Rocket informs you of the error at compile-time with a helpful
|
|
||||||
message:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
error: person route uri expects 2 parameters but 1 was supplied
|
|
||||||
--> examples/uri/src/main.rs:9:29
|
|
||||||
|
|
|
||||||
9 | uri!(person: "Mike Smith");
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: expected parameters: name: String, age: Option<u8>
|
|
||||||
```
|
|
||||||
|
|
||||||
The same applies to type errors: Rocket informs you of any type errors at
|
|
||||||
compile-time as well:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
error: the trait bound u8: FromUriParam<Query, &str> is not satisfied
|
|
||||||
--> examples/uri/src/main.rs:9:35
|
|
||||||
|
|
|
||||||
9 | uri!(person: age = "10", name = "Mike");
|
|
||||||
| ^^^^ FromUriParam<Query, &str> is not implemented for u8
|
|
||||||
|
|
|
||||||
```
|
|
||||||
|
|
||||||
We recommend that `uri!` is exclusively used when constructing route URIs. For
|
|
||||||
more information on typed URIs, see the new [Typed URIs] guide section and the
|
|
||||||
[`uri!`] macro documentation.
|
|
||||||
|
|
||||||
[`uri!`]: @api-v0.4/rocket_codegen/macro.uri.html
|
|
||||||
[Typed URIs]: @guide-v0.4/responses/#typed-uris
|
|
||||||
|
|
||||||
### Database Support
|
|
||||||
|
|
||||||
Rocket now includes built-in, ORM-agnostic support for database connection
|
|
||||||
pooling. More specifically, Rocket allows you to easily configure and connect
|
|
||||||
your Rocket application to databases through connection pools in three simple,
|
|
||||||
largely automated steps:
|
|
||||||
|
|
||||||
1. Configure databases in `Rocket.toml`.
|
|
||||||
2. Associate a request guard type and fairing with each database.
|
|
||||||
3. Use the request guard to retrieve a connection in a handler.
|
|
||||||
|
|
||||||
As an example, for a Diesel-based SQLite database named `sqlite_logs`, your
|
|
||||||
`Rocket.toml` would record the URL to the database in the `databases` table:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[global.databases]
|
|
||||||
sqlite_logs = { url = "/path/to/database.sqlite" }
|
|
||||||
```
|
|
||||||
|
|
||||||
In the application, a unit-like `struct` with one internal type (the database
|
|
||||||
connection) is decorated with the `#[database]` attribute and the name of the
|
|
||||||
configured database. This generates a fairing which must then be attached:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[database("sqlite_logs")]
|
|
||||||
struct LogsDbConn(diesel::SqliteConnection);
|
|
||||||
|
|
||||||
rocket::ignite().attach(LogsDbConn::fairing())
|
|
||||||
```
|
|
||||||
|
|
||||||
That's it! Whenever a connection to the database is needed, the type can be used
|
|
||||||
as a request guard:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[get("/logs/<id>")]
|
|
||||||
fn get_logs(conn: LogsDbConn, id: usize) -> Result<Logs> {
|
|
||||||
logs::filter(id.eq(log_id)).load(&conn)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For more information on Rocket's database support, see the new [Database] guide
|
|
||||||
section and the [`rocket_contrib::databases`] module documentation.
|
|
||||||
|
|
||||||
[Database]: @guide-v0.4/state/#databases
|
|
||||||
[`rocket_contrib::databases`]: @api-v0.4/rocket_contrib/databases/index.html
|
|
||||||
|
|
||||||
### Revamped Queries
|
|
||||||
|
|
||||||
In Rocket 0.4, query string handling has been completely overhauled, resolving
|
|
||||||
some of the most called for requests in Rocket's history ([#608]). The new query
|
|
||||||
handling route syntax and semantics were designed with the following goals in
|
|
||||||
mind:
|
|
||||||
|
|
||||||
* Enable matching of static query components.
|
|
||||||
* No special-casing of any kind, preferring type-driven flows.
|
|
||||||
* Ad-hoc matching of specific query key/value pairs.
|
|
||||||
* Lenient parsing by default, allowing missing parameters.
|
|
||||||
* Order-independent matching of query parameters.
|
|
||||||
|
|
||||||
To illustrate the new system in action, consider the following route:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[derive(FromForm)]
|
|
||||||
struct DogDetails {
|
|
||||||
color: Color,
|
|
||||||
height: Inches,
|
|
||||||
weight: Pounds
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/animal?dog&<name>&<nickname>&<rest..>")]
|
|
||||||
fn dog(name: String, nickname: Option<String>, rest: Form<DogDetails>)
|
|
||||||
```
|
|
||||||
|
|
||||||
This route matches any `GET` request with a path of `/animal`, a static query
|
|
||||||
component of `dog`, and key/value parameters of `color`, `height`, and `weight`
|
|
||||||
that validate as `Color`, `Inches`, and `Pounds`, respectively. Furthermore, it
|
|
||||||
optionally accepts a key/value parameter of `nickname`. If the value is present,
|
|
||||||
`nickname` will be `Some`; if it is not, `nickname` will be `None`.
|
|
||||||
|
|
||||||
Single parameters (`<param>`) like `name` and `nickname` are validated using the
|
|
||||||
existing [`FromFormValue`] trait while trailing parameters (`<param..>`) are
|
|
||||||
validated using the new [`FromQuery`] trait. Both traits are user implementable,
|
|
||||||
and [`FromFormValue`] can be derived.
|
|
||||||
|
|
||||||
For more details on handling query strings, see the new [Query Strings] guide
|
|
||||||
section and the updated [`route` attribute] documentation.
|
|
||||||
|
|
||||||
[`FromFormValue`]: @api-v0.4/rocket/request/trait.FromFormValue.html
|
|
||||||
[`FromQuery`]: @api-v0.4/rocket/request/trait.FromQuery.html
|
|
||||||
[`route` attribute]: @api-v0.4/rocket_codegen/attr.get.html
|
|
||||||
[Query Strings]: @guide-v0.4/requests/#query-strings
|
|
||||||
[#608]: https://github.com/rwf2/Rocket/issues/608
|
|
||||||
|
|
||||||
### Stateful Handlers
|
|
||||||
|
|
||||||
The type of a handler has been generalized in 0.4 to any type that implements
|
|
||||||
the new [`Handler`] trait. Among other things, this allows handlers to refer to
|
|
||||||
internal state during request handling.
|
|
||||||
|
|
||||||
The new [`StaticFiles`] `contrib` type uses this functionality to provide
|
|
||||||
easier-than-ever static file serving. For example, to make local files from a
|
|
||||||
`/static` directory accessible at `/public`, you need simply write:
|
|
||||||
|
|
||||||
|
|
||||||
```rust
|
|
||||||
fn main() {
|
|
||||||
rocket::ignite()
|
|
||||||
.mount("/public", StaticFiles::from("/static"))
|
|
||||||
.launch();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
We encourage users to explore the new `Handler` API and contribute libraries
|
|
||||||
with pluggable handlers! For more details, see the [`Handler`] documentation.
|
|
||||||
|
|
||||||
[`Handler`]: @api-v0.4/rocket/trait.Handler.html
|
|
||||||
[`StaticFiles`]: @api-v0.4/rocket_contrib/serve/struct.StaticFiles.html
|
|
||||||
|
|
||||||
### Responder Derive
|
|
||||||
|
|
||||||
In Rocket 0.4, the [`Responder`] trait can be derived for `enum`s and `struct`s
|
|
||||||
with named fields. This greatly simplifies returning multiple types of responses
|
|
||||||
from a single handler.
|
|
||||||
|
|
||||||
To illustrate, consider a route that returns either a `Json<Info>` structure for
|
|
||||||
401 (unauthorized) errors or a `NamedFile` with a dynamic Content-Type for 404
|
|
||||||
(not found) errors. To accomplish this previously, `Result` values could be
|
|
||||||
arbitrarily nested, an unappealing and semantically incorrect approach.
|
|
||||||
Alternatively, an `enum` could be declared with the appropriate variants, and
|
|
||||||
`Responder` could be manually implemented for the `enum`. As of 0.4, that
|
|
||||||
implementation can be automatically derived:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[derive(Responder, Debug)]
|
|
||||||
enum Error {
|
|
||||||
#[response(status = 401)]
|
|
||||||
Unauthorized(Json<Info>),
|
|
||||||
#[response(status = 404)]
|
|
||||||
NotFound(NamedFile, ContentType),
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
A value of this type can then be returned from a handler or used as part of
|
|
||||||
wrapping responders:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[get("/<item>")]
|
|
||||||
fn handler(user: Option<User>, item: Option<Item>) -> Result<T, Error> {
|
|
||||||
if user.is_none() {
|
|
||||||
Err(Error::Unauthorized(..))
|
|
||||||
} else if item.is_none() {
|
|
||||||
Err(Error::NotFound(..))
|
|
||||||
} else {
|
|
||||||
Ok(..)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The status for each variant will be automatically set to the value of the
|
|
||||||
`status` variant attribute, and fields beyond the first will be added as
|
|
||||||
headers to the response (here, `ContentType`).
|
|
||||||
|
|
||||||
For more on using the `Responder` derive, see the new [Custom Responders] guide
|
|
||||||
section and the [`Responder` derive] documentation.
|
|
||||||
|
|
||||||
[Custom Responders]: @guide-v0.4/responses/#custom-responders
|
|
||||||
[`Responder` derive]: @api-v0.4/rocket_codegen/derive.Responder.html
|
|
||||||
[`Responder`]: @api-v0.4/rocket/response/trait.Responder.html
|
|
||||||
|
|
||||||
### Live Template Reloading
|
|
||||||
|
|
||||||
Rocket 0.4 automatically reloads changed templates at runtime without requiring
|
|
||||||
recompilation. This works on all major platforms. For security and performance
|
|
||||||
reasons, live template reloading is only enabled when the application is
|
|
||||||
compiled in debug mode.
|
|
||||||
|
|
||||||
There is no configuration necessary: this _just works_ out of the box!
|
|
||||||
|
|
||||||
### And Plenty More!
|
|
||||||
|
|
||||||
In addition to the features highlighted above, Rocket 0.4 also contains the
|
|
||||||
following new features:
|
|
||||||
|
|
||||||
* Introduced [Request-Local State].
|
|
||||||
* Introduced [transforming] data guards via [`FromData::transform()`].
|
|
||||||
* Introduced the [`SpaceHelmet`] security and privacy headers fairing.
|
|
||||||
* Private cookies are gated behind a `private-cookies` default feature.
|
|
||||||
* Added [derive for `FromFormValue`].
|
|
||||||
* Added [`Template::custom()`] for customizing templating engines.
|
|
||||||
* Cookies are automatically tracked and propagated by [`Client`].
|
|
||||||
* Private cookies can be added to local requests with
|
|
||||||
[`LocalRequest::private_cookie()`].
|
|
||||||
* Release builds default to the `production` environment.
|
|
||||||
* Keep-alive can be configured via the `keep_alive` configuration parameter.
|
|
||||||
* Allow CLI colors and emoji to be disabled with `ROCKET_CLI_COLORS=off`.
|
|
||||||
* Route `format` accepts [shorthands] such as `json` and `html`.
|
|
||||||
* Implemented [`Responder` for `Status`].
|
|
||||||
* Added [`Response::cookies()`] for retrieving response cookies.
|
|
||||||
* All logging is disabled when `log` is set to `off`.
|
|
||||||
* Added [`Metadata`] guard for retrieving templating information.
|
|
||||||
* The [`Uri`] type parses according to RFC 7230 into one of [`Origin`],
|
|
||||||
[`Absolute`], or [`Authority`].
|
|
||||||
* Added [`Outcome::and_then()`], [`Outcome::failure_then()`], and
|
|
||||||
[`Outcome::forward_then()`].
|
|
||||||
* Implemented `Responder` for `&[u8]`.
|
|
||||||
* Any `T: Into<Vec<Route>>` can be [`mount()`]ed.
|
|
||||||
* Added [`Request::get_query_value()`] for retrieving a query value by key.
|
|
||||||
* Applications can launch without a working directory.
|
|
||||||
* Added [`State::from()`] for constructing `State` values.
|
|
||||||
|
|
||||||
[`SpaceHelmet`]: https://api.rocket.rs/v0.4/rocket_contrib/helmet/index.html
|
|
||||||
[`State::from()`]: https://api.rocket.rs/v0.4/rocket/struct.State.html#method.from
|
|
||||||
[Typed URIs]: https://rocket.rs/v0.4/guide/responses/#typed-uris
|
|
||||||
[ORM agnostic database support]: https://rocket.rs/v0.4/guide/state/#databases
|
|
||||||
[`Template::custom()`]: https://api.rocket.rs/v0.4/rocket_contrib/templates/struct.Template.html#method.custom
|
|
||||||
[`LocalRequest::private_cookie()`]: https://api.rocket.rs/v0.4/rocket/local/struct.LocalRequest.html#method.private_cookie
|
|
||||||
[`LocalRequest`]: https://api.rocket.rs/v0.4/rocket/local/struct.LocalRequest.html
|
|
||||||
[shorthands]: https://api.rocket.rs/v0.4/rocket/http/struct.ContentType.html#method.parse_flexible
|
|
||||||
[derive for `FromFormValue`]: https://api.rocket.rs/v0.4/rocket_codegen/derive.FromFormValue.html
|
|
||||||
[derive for `Responder`]: https://api.rocket.rs/v0.4/rocket_codegen/derive.Responder.html
|
|
||||||
[`Response::cookies()`]: https://api.rocket.rs/v0.4/rocket/struct.Response.html#method.cookies
|
|
||||||
[`Client`]: https://api.rocket.rs/v0.4/rocket/local/struct.Client.html
|
|
||||||
[Request-Local State]: https://rocket.rs/v0.4/guide/state/#request-local-state
|
|
||||||
[`Metadata`]: https://api.rocket.rs/v0.4/rocket_contrib/templates/struct.Metadata.html
|
|
||||||
[`Uri`]: https://api.rocket.rs/v0.4/rocket/http/uri/enum.Uri.html
|
|
||||||
[`Origin`]: https://api.rocket.rs/v0.4/rocket/http/uri/struct.Origin.html
|
|
||||||
[`Absolute`]: https://api.rocket.rs/v0.4/rocket/http/uri/struct.Absolute.html
|
|
||||||
[`Authority`]: https://api.rocket.rs/v0.4/rocket/http/uri/struct.Authority.html
|
|
||||||
[`Outcome::and_then()`]: https://api.rocket.rs/v0.4/rocket/enum.Outcome.html#method.and_then
|
|
||||||
[`Outcome::forward_then()`]: https://api.rocket.rs/v0.4/rocket/enum.Outcome.html#method.forward_then
|
|
||||||
[`Outcome::failure_then()`]: https://api.rocket.rs/v0.4/rocket/enum.Outcome.html#method.failure_then
|
|
||||||
[`StaticFiles`]: https://api.rocket.rs/v0.4/rocket_contrib/serve/struct.StaticFiles.html
|
|
||||||
[live template reloading]: https://rocket.rs/v0.4/guide/responses/#live-reloading
|
|
||||||
[`Handler`]: https://api.rocket.rs/v0.4/rocket/trait.Handler.html
|
|
||||||
[`mount()`]: https://api.rocket.rs/v0.4/rocket/struct.Rocket.html#method.mount
|
|
||||||
[`FromData::transform()`]: https://api.rocket.rs/v0.4/rocket/data/trait.FromData.html#tymethod.transform
|
|
||||||
[transforming]: https://api.rocket.rs/v0.4/rocket/data/trait.FromData.html#transforming
|
|
||||||
[query string handling]: https://rocket.rs/v0.4/guide/requests/#query-strings
|
|
||||||
[Default rankings]: https://rocket.rs/v0.4/guide/requests/#default-ranking
|
|
||||||
[`Request::get_query_value()`]: https://api.rocket.rs/v0.4/rocket/struct.Request.html#method.get_query_value
|
|
||||||
[`Responder` for `Status`]: https://rocket.rs/v0.4/guide/responses/#status
|
|
||||||
|
|
||||||
## Breaking Changes
|
|
||||||
|
|
||||||
This release includes many breaking changes. Please see the
|
|
||||||
[CHANGELOG](https://github.com/rwf2/Rocket/blob/v0.3.0/CHANGELOG.md#breaking-changes)
|
|
||||||
for a complete list of breaking changes along with details on handling the
|
|
||||||
breaking change in existing applications.
|
|
||||||
|
|
||||||
Rocket 0.3 will continue as a security maintenance release _only_. All users are
|
|
||||||
encouraged to migrate their applications to 0.4.
|
|
||||||
|
|
||||||
## General Improvements
|
|
||||||
|
|
||||||
In addition to new features, Rocket saw the following improvements:
|
|
||||||
|
|
||||||
* Log messages now refer to routes by name.
|
|
||||||
* Collision errors on launch name the colliding routes.
|
|
||||||
* Launch fairing failures refer to the failing fairing by name.
|
|
||||||
* The default `403` catcher now references authorization, not authentication.
|
|
||||||
* Private cookies are set to `HttpOnly` and are given an expiration date of 1
|
|
||||||
week by default.
|
|
||||||
* A [Tera templates example] was added.
|
|
||||||
* All macros, derives, and attributes are individually documented in
|
|
||||||
[`rocket_codegen`].
|
|
||||||
* Invalid client requests receive a response of `400` instead of `500`.
|
|
||||||
* Response bodies are reliably stripped on `HEAD` requests.
|
|
||||||
* Added a default catcher for `504: Gateway Timeout`.
|
|
||||||
* Configuration information is logged in all environments.
|
|
||||||
* Use of `unsafe` was reduced from 9 to 2 in core library.
|
|
||||||
* [`FormItems`] now parses empty keys and values as well as keys without
|
|
||||||
values.
|
|
||||||
* Added [`Config::active()`] as a shorthand for
|
|
||||||
`Config::new(Environment::active()?)`.
|
|
||||||
* Address/port binding errors at launch are detected and explicitly emitted.
|
|
||||||
* [`Flash`] cookies are cleared only after they are inspected.
|
|
||||||
* `Sync` bound on [`AdHoc::on_attach()`], [`AdHoc::on_launch()`] was removed.
|
|
||||||
* [`AdHoc::on_attach()`], [`AdHoc::on_launch()`] accept an `FnOnce`.
|
|
||||||
* Added [`Config::root_relative()`] for retrieving paths relative to the
|
|
||||||
configuration file.
|
|
||||||
* Added [`Config::tls_enabled()`] for determining whether TLS is actively
|
|
||||||
enabled.
|
|
||||||
* ASCII color codes are not emitted on versions of Windows that do not support
|
|
||||||
them.
|
|
||||||
* Added FLAC (`audio/flac`), Icon (`image/x-icon`), WEBA (`audio/webm`), TIFF
|
|
||||||
(`image/tiff`), AAC (`audio/aac`), Calendar (`text/calendar`), MPEG
|
|
||||||
(`video/mpeg`), TAR (`application/x-tar`), GZIP (`application/gzip`), MOV
|
|
||||||
(`video/quicktime`), MP4 (`video/mp4`), ZIP (`application/zip`) as known
|
|
||||||
media types.
|
|
||||||
* Added `.weba` (`WEBA`), `.ogv` (`OGG`), `.mp4` (`MP4`), `.mpeg4` (`MP4`),
|
|
||||||
`.aac` (`AAC`), `.ics` (`Calendar`), `.bin` (`Binary`), `.mpg` (`MPEG`),
|
|
||||||
`.mpeg` (`MPEG`), `.tar` (`TAR`), `.gz` (`GZIP`), `.tif` (`TIFF`), `.tiff`
|
|
||||||
(`TIFF`), `.mov` (`MOV`) as known extensions.
|
|
||||||
* Interaction between route attributes and declarative macros has been
|
|
||||||
improved.
|
|
||||||
* Generated code now logs through logging infrastructures as opposed to using
|
|
||||||
`println!`.
|
|
||||||
* Routing has been optimized by caching routing metadata.
|
|
||||||
* [`Form`] and [`LenientForm`] can be publicly constructed.
|
|
||||||
* Console coloring uses default terminal colors instead of white.
|
|
||||||
* Console coloring is consistent across all messages.
|
|
||||||
* `i128` and `u128` now implement [`FromParam`], [`FromFormValue`].
|
|
||||||
* The `base64` dependency was updated to `0.10`.
|
|
||||||
* The `log` dependency was updated to `0.4`.
|
|
||||||
* The `handlebars` dependency was updated to `1.0`.
|
|
||||||
* The `tera` dependency was updated to `0.11`.
|
|
||||||
* The `uuid` dependency was updated to `0.7`.
|
|
||||||
* The `rustls` dependency was updated to `0.14`.
|
|
||||||
* The `cookie` dependency was updated to `0.11`.
|
|
||||||
|
|
||||||
[Tera templates example]: @github/examples/tera_templates
|
|
||||||
[`FormItems`]: @api-v0.4/rocket/request/enum.FormItems.html
|
|
||||||
[`Config::active()`]: @api-v0.4/rocket/config/struct.Config.html#method.active
|
|
||||||
[`Flash`]: @api-v0.4/rocket/response/struct.Flash.html
|
|
||||||
[`AdHoc::on_attach()`]: @api-v0.4/rocket/fairing/struct.AdHoc.html#method.on_attach
|
|
||||||
[`AdHoc::on_launch()`]: @api-v0.4/rocket/fairing/struct.AdHoc.html#method.on_launch
|
|
||||||
[`Config::root_relative()`]: @api-v0.4/rocket/struct.Config.html#method.root_relative
|
|
||||||
[`Config::tls_enabled()`]: @api-v0.4/rocket/struct.Config.html#method.tls_enabled
|
|
||||||
[`rocket_codegen`]: @api-v0.4/rocket_codegen/index.html
|
|
||||||
[`FromParam`]: @api-v0.4/rocket/request/trait.FromParam.html
|
|
||||||
[`FromFormValue`]: @api-v0.4/rocket/request/trait.FromFormValue.html
|
|
||||||
[`Data`]: @api-v0.4/rocket/struct.Data.html
|
|
||||||
[`Form`]: https://api.rocket.rs/v0.4/rocket/request/struct.Form.html
|
|
||||||
[`LenientForm`]: https://api.rocket.rs/v0.4/rocket/request/struct.LenientForm.html
|
|
||||||
|
|
||||||
## What's Next?
|
|
||||||
|
|
||||||
Rocket v0.5 is scheduled to be _at least_ as exciting as 0.4! As always, the
|
|
||||||
focus continues to be usability, stability, security, and performance. With this
|
|
||||||
in mind, the roadmap for 0.5 includes:
|
|
||||||
|
|
||||||
1. **Support for Rust Stable** ([#19])
|
|
||||||
|
|
||||||
Finally! Rocket 0.5 will compile and run on stable versions of the Rust
|
|
||||||
compiler.
|
|
||||||
|
|
||||||
2. **Asynchronous Request Handling** ([#17])
|
|
||||||
|
|
||||||
In 0.5, Rocket will migrate to the latest asynchronous version of `hyper` and
|
|
||||||
`futures` with compatibility for `async`/`await` syntax. Of utmost importance
|
|
||||||
is preserving Rocket's usability. As such, these changes will be largely
|
|
||||||
internal, with asynchronous I/O peeking over the covers _only_ when
|
|
||||||
explicitly desired or required. As a side effect, we expect a substantial
|
|
||||||
performance boost from the migration as well as resolution to long-standing
|
|
||||||
issues.
|
|
||||||
|
|
||||||
3. **Multipart Form Support** ([#106])
|
|
||||||
|
|
||||||
The lack of built-in multipart form support makes handling file uploads and
|
|
||||||
other submissions much more cumbersome than necessary. Rocket 0.5 will
|
|
||||||
generalize its existing forms infrastructure to handle multipart forms.
|
|
||||||
|
|
||||||
4. **Stronger CSRF and XSS Protection** ([#14])
|
|
||||||
|
|
||||||
Since 0.3, Rocket uses `SameSite: Strict` private cookies to prevent CSRF
|
|
||||||
attacks. This technique is only tenable in newer browsers. In 0.5, Rocket
|
|
||||||
will protect against CSRF using more robust techniques. Rocket will also add
|
|
||||||
support for automatic, browser-based XSS protection.
|
|
||||||
|
|
||||||
[#17]: https://github.com/rwf2/Rocket/issues/17
|
|
||||||
[#19]: https://github.com/rwf2/Rocket/issues/19
|
|
||||||
[#106]: https://github.com/rwf2/Rocket/issues/106
|
|
||||||
[#14]: https://github.com/rwf2/Rocket/issues/14
|
|
||||||
|
|
||||||
## Rocket v0.4 Contributors
|
|
||||||
|
|
||||||
The following wonderful people helped make Rocket 0.4 happen:
|
|
||||||
|
|
||||||
<ul class="columns">
|
|
||||||
<li>Alexander Mielczarek</li>
|
|
||||||
<li>Alex Bowers</li>
|
|
||||||
<li>Alfie John</li>
|
|
||||||
<li>Alva Snædís</li>
|
|
||||||
<li>Ashley Williams</li>
|
|
||||||
<li>Beatriz Rizental</li>
|
|
||||||
<li>bohov</li>
|
|
||||||
<li>Christophe Courtaut</li>
|
|
||||||
<li>David Darrell</li>
|
|
||||||
<li>Desmond</li>
|
|
||||||
<li>Divyahans Gupta</li>
|
|
||||||
<li>Donald Robertson</li>
|
|
||||||
<li>EloD10</li>
|
|
||||||
<li>Eric Dattore</li>
|
|
||||||
<li>Henning Kowalk</li>
|
|
||||||
<li>Imron Alston</li>
|
|
||||||
<li>Jeb Rosen</li>
|
|
||||||
<li>kryptan</li>
|
|
||||||
<li>Kyle Clemens</li>
|
|
||||||
<li>lerina</li>
|
|
||||||
<li>Linus Unnebäck</li>
|
|
||||||
<li>Lukas Abfalterer</li>
|
|
||||||
<li>Marc Mettke</li>
|
|
||||||
<li>Max Furman</li>
|
|
||||||
<li>messense</li>
|
|
||||||
<li>Ning Sun</li>
|
|
||||||
<li>Philip Jenvey</li>
|
|
||||||
<li>Pyry Kontio</li>
|
|
||||||
<li>Richo Healey</li>
|
|
||||||
<li>Riley Trautman</li>
|
|
||||||
<li>Rolf Schmidt</li>
|
|
||||||
<li>Rukai</li>
|
|
||||||
<li>Sean Stangl</li>
|
|
||||||
<li>Sébastien Santoro</li>
|
|
||||||
<li>Sergio Benitez</li>
|
|
||||||
<li>Stanislav Ivanov</li>
|
|
||||||
<li>Tal Garfinkel</li>
|
|
||||||
<li>Tobias Stolzmann</li>
|
|
||||||
<li>Ville Hakulinen</li>
|
|
||||||
<li>Vishal Sodani</li>
|
|
||||||
<li>Zack Chandler</li>
|
|
||||||
<li>Zac Pullar-Strecker</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
Thank you all! Your contributions are **greatly** appreciated!
|
|
||||||
|
|
||||||
Looking to help with Rocket's development? Head over to [Rocket's
|
|
||||||
GitHub](https://github.com/rwf2/Rocket#contributing) and start
|
|
||||||
contributing!
|
|
|
@ -1,43 +0,0 @@
|
||||||
# Rocket v0.5 Release Candidate
|
|
||||||
|
|
||||||
<p class="metadata"><strong>
|
|
||||||
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on June 09, 2021
|
|
||||||
</strong></p>
|
|
||||||
|
|
||||||
Rocket `0.5.0-rc.1`, a release candidate for Rocket v0.5, is now available.
|
|
||||||
|
|
||||||
This release actualizes over _two years_ of development, bringing Rocket to Rust
|
|
||||||
stable and `async` to Rocket. Every facet, from core request handling to error
|
|
||||||
messages, has been subjected to Rocket's exacting standards.
|
|
||||||
|
|
||||||
This release candidate is an opportunity to discover issues with Rocket v0.5 and
|
|
||||||
its documentation before a general release. We encourage all users to migrate
|
|
||||||
their applications to the release candidate. All documentation, including the
|
|
||||||
[guide] and [API docs], has been updated in full for v0.5. Please report issues
|
|
||||||
to the [GitHub issue tracker]. Questions or concerns should instead be raised on
|
|
||||||
Rocket's newly available [GitHub discussions].
|
|
||||||
|
|
||||||
The Rocket v0.5 general release is planned for Friday, June 18th. A complete
|
|
||||||
migration guide and news article will accompany the general release. Until then,
|
|
||||||
the [CHANGELOG] contains every feature addition, change, and improvement since
|
|
||||||
v0.4.
|
|
||||||
|
|
||||||
We hope you enjoy Rocket v0.5 as much as we enjoyed creating it. We look forward
|
|
||||||
to your feedback!
|
|
||||||
|
|
||||||
[GitHub issue tracker]: https://github.com/rwf2/Rocket/issues
|
|
||||||
[GitHub discussions]: https://github.com/rwf2/Rocket/discussions
|
|
||||||
[CHANGELOG]: https://github.com/rwf2/Rocket/blob/v0.5.0-rc.1/CHANGELOG.md
|
|
||||||
[API docs]: @api-v0.5
|
|
||||||
[guide]: @guide-v0.5
|
|
||||||
|
|
||||||
## About Rocket
|
|
||||||
|
|
||||||
Rocket is a web framework for Rust with a focus on usability, security,
|
|
||||||
extensibility, and speed. Rocket makes it simple to write fast, secure web
|
|
||||||
applications without sacrificing usability.
|
|
||||||
|
|
||||||
Not already using Rocket? Join the tens of thousands of users and hundreds of
|
|
||||||
companies happily using Rocket today! Rocket's extensive documentation makes it
|
|
||||||
easy: get started by [reading through the guide](../../guide) or learning more
|
|
||||||
from [the overview](../../overview).
|
|
|
@ -1,43 +0,0 @@
|
||||||
# Rocket's 2nd v0.5 Release Candidate
|
|
||||||
|
|
||||||
<p class="metadata"><strong>
|
|
||||||
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on May 09, 2022
|
|
||||||
</strong></p>
|
|
||||||
|
|
||||||
Rocket `0.5.0-rc.2`, a release candidate for Rocket v0.5, is now available.
|
|
||||||
|
|
||||||
This release builds on the previous release candidate and brings further
|
|
||||||
features, improvements, and fixes to Rocket. As before, this is an opportunity
|
|
||||||
to discover issues with Rocket v0.5 and its documentation before its general
|
|
||||||
release. We encourage all users to migrate their applications to the second
|
|
||||||
release candidate and report any issues to the [GitHub issue tracker]. Please
|
|
||||||
see the new [migration guide] for complete details on how to upgrade from Rocket
|
|
||||||
v0.4. For changes since Rocket v0.5.0-rc.1, please see the [CHANGELOG].
|
|
||||||
|
|
||||||
Barring any major issues, of which none are expected, the general release of
|
|
||||||
Rocket v0.5 is planned for late May 2022, when we'll post a full news article
|
|
||||||
covering the biggest features and changes in Rocket v0.5. Until then, the
|
|
||||||
[CHANGELOG] contains every feature addition, change, and improvement since
|
|
||||||
v0.5.0-rc.1 and v0.4. All documentation, including the [guide] and [API docs],
|
|
||||||
has been updated in full for the second release candidate.
|
|
||||||
|
|
||||||
We're excited for your feedback, and we look forward to seeing you again soon
|
|
||||||
for the general release!
|
|
||||||
|
|
||||||
[GitHub issue tracker]: https://github.com/rwf2/Rocket/issues
|
|
||||||
[GitHub discussions]: https://github.com/rwf2/Rocket/discussions
|
|
||||||
[migration guide]: @guide-v0.5/upgrading
|
|
||||||
[CHANGELOG]: https://github.com/rwf2/Rocket/blob/v0.5.0-rc.2/CHANGELOG.md
|
|
||||||
[API docs]: @api-v0.5
|
|
||||||
[guide]: @guide-v0.5
|
|
||||||
|
|
||||||
## About Rocket
|
|
||||||
|
|
||||||
Rocket is a web framework for Rust with a focus on usability, security,
|
|
||||||
extensibility, and speed. Rocket makes it simple to write fast, secure web
|
|
||||||
applications without sacrificing usability.
|
|
||||||
|
|
||||||
Not already using Rocket? Join the tens of thousands of users and hundreds of
|
|
||||||
companies happily using Rocket today! Rocket's extensive documentation makes it
|
|
||||||
easy: get started by [reading through the guide](../../guide) or learning more
|
|
||||||
from [the overview](../../overview).
|
|
|
@ -1,31 +0,0 @@
|
||||||
# Rocket's 3rd v0.5 Release Candidate
|
|
||||||
|
|
||||||
<p class="metadata"><strong>
|
|
||||||
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on March 23, 2023
|
|
||||||
</strong></p>
|
|
||||||
|
|
||||||
Rocket `0.5.0-rc.3`, a release candidate for Rocket v0.5, is now available.
|
|
||||||
|
|
||||||
This release builds on the previous release candidate and brings further
|
|
||||||
features, improvements, and fixes to Rocket. As before, this is an opportunity
|
|
||||||
to discover issues with Rocket v0.5 and its documentation before its general
|
|
||||||
release. We encourage all users to migrate their applications to the third
|
|
||||||
release candidate and report any issues to the [GitHub issue tracker]. Please
|
|
||||||
see the new [migration guide] for complete details on how to upgrade from Rocket
|
|
||||||
v0.4. For changes since Rocket v0.5.0-rc.2, please see the [CHANGELOG].
|
|
||||||
|
|
||||||
[GitHub issue tracker]: https://github.com/rwf2/Rocket/issues
|
|
||||||
[GitHub discussions]: https://github.com/rwf2/Rocket/discussions
|
|
||||||
[migration guide]: @guide-v0.5/upgrading
|
|
||||||
[CHANGELOG]: https://github.com/rwf2/Rocket/blob/v0.5.0-rc.3/CHANGELOG.md
|
|
||||||
|
|
||||||
## About Rocket
|
|
||||||
|
|
||||||
Rocket is a web framework for Rust with a focus on usability, security,
|
|
||||||
extensibility, and speed. Rocket makes it simple to write fast, secure web
|
|
||||||
applications without sacrificing usability.
|
|
||||||
|
|
||||||
Not already using Rocket? Join the tens of thousands of users and hundreds of
|
|
||||||
companies happily using Rocket today! Rocket's extensive documentation makes it
|
|
||||||
easy: get started by [reading through the guide](../../guide) or learning more
|
|
||||||
from [the overview](../../overview).
|
|
|
@ -1,31 +0,0 @@
|
||||||
# Rocket's 4th v0.5 Release Candidate
|
|
||||||
|
|
||||||
<p class="metadata"><strong>
|
|
||||||
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on November 01, 2023
|
|
||||||
</strong></p>
|
|
||||||
|
|
||||||
Rocket `0.5.0-rc.4`, a release candidate for Rocket v0.5, is now available.
|
|
||||||
|
|
||||||
This release builds on the previous release candidate and brings further
|
|
||||||
features, improvements, and fixes to Rocket. As before, this is an opportunity
|
|
||||||
to discover issues with Rocket v0.5 and its documentation before its general
|
|
||||||
release. We encourage all users to migrate their applications to the fourth
|
|
||||||
release candidate and report any issues to the [GitHub issue tracker]. Please
|
|
||||||
see the new [migration guide] for complete details on how to upgrade from Rocket
|
|
||||||
v0.4. For changes since Rocket v0.5.0-rc.3, please see the [CHANGELOG].
|
|
||||||
|
|
||||||
[GitHub issue tracker]: https://github.com/rwf2/Rocket/issues
|
|
||||||
[GitHub discussions]: https://github.com/rwf2/Rocket/discussions
|
|
||||||
[migration guide]: @guide-v0.5/upgrading
|
|
||||||
[CHANGELOG]: https://github.com/rwf2/Rocket/blob/v0.5.0-rc.4/CHANGELOG.md
|
|
||||||
|
|
||||||
## About Rocket
|
|
||||||
|
|
||||||
Rocket is a web framework for Rust with a focus on usability, security,
|
|
||||||
extensibility, and speed. Rocket makes it simple to write fast, secure web
|
|
||||||
applications without sacrificing usability.
|
|
||||||
|
|
||||||
Not already using Rocket? Join the tens of thousands of users and hundreds of
|
|
||||||
companies happily using Rocket today! Rocket's extensive documentation makes it
|
|
||||||
easy: get started by [reading through the guide](../../guide) or learning more
|
|
||||||
from [the overview](../../overview).
|
|
|
@ -1,253 +0,0 @@
|
||||||
# Building a Better Foundation for Rocket's Future
|
|
||||||
|
|
||||||
<p class="metadata"><strong>
|
|
||||||
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on Nov 17, 2023
|
|
||||||
</strong></p>
|
|
||||||
|
|
||||||
Along with the [release of Rocket v0.5], today I'm sharing plans to launch the
|
|
||||||
Rocket Web Framework Foundation, or [_RWF2_]. The RWF2 is a nonprofit
|
|
||||||
organization designed to support Rocket and the surrounding ecosystem,
|
|
||||||
financially and organizationally.
|
|
||||||
|
|
||||||
I'm also directly addressing the community's concerns regarding the pace of
|
|
||||||
Rocket's development, leadership, and release cadence. My hope is to assuage any
|
|
||||||
and all concerns about Rocket's future. I hope reading this leaves you feeling
|
|
||||||
confident that Rocket is here to stay, and that the RWF2 is the right step
|
|
||||||
towards increased community contributions and involvement.
|
|
||||||
|
|
||||||
! note: This is a co-announcement [along with release of Rocket v0.5].
|
|
||||||
|
|
||||||
[along with release of Rocket v0.5]: ../2023-11-17-version-0.5/
|
|
||||||
[release of Rocket v0.5]: ../2023-11-17-version-0.5/
|
|
||||||
[_RWF2_]: https://rwf2.org
|
|
||||||
[RWF2]: https://rwf2.org
|
|
||||||
|
|
||||||
## Background
|
|
||||||
|
|
||||||
I released Rocket in 2016 to fanfare. It was lauded as _the_ web framework for
|
|
||||||
Rust. But in the last few years, I'd be remiss to claim the same. New frameworks
|
|
||||||
have emerged, Rocket's recent development has been nothing short of erratic, and
|
|
||||||
four years went by without a major release.
|
|
||||||
|
|
||||||
The community rightfully voiced its disappointment and concern. Posts inquired
|
|
||||||
about the project's status: was it dead? I received copious email ranging from
|
|
||||||
concern over my well-being, to anger, to requests to transfer the project
|
|
||||||
entirely. The community ~~wasn't~~ isn't happy with Rocket.
|
|
||||||
|
|
||||||
And I get it. I failed to adequately lead the project. I failed to communicate
|
|
||||||
when it mattered most. I couldn't control the life events that pulled me away
|
|
||||||
from Rocket and most of my responsibilities, but I could have done more to
|
|
||||||
communicate what was going on. And I certainly could have done _something_ to
|
|
||||||
make it easy, make it _possible_ for others to push the project forward in my
|
|
||||||
absense.
|
|
||||||
|
|
||||||
But I did none of that. I couldn't make it happen. And I'm truly, sincerely
|
|
||||||
sorry.
|
|
||||||
|
|
||||||
## A Better Foundation for Rocket's Future
|
|
||||||
|
|
||||||
I'd like to make it impossible to repeat these mistakes. That's why today I'm
|
|
||||||
announcing plans for a new independent nonprofit foundation designed to support
|
|
||||||
and bolster Rocket's development, increase transparency, and diversify project
|
|
||||||
leadership: [RWF2].
|
|
||||||
|
|
||||||
> The **R**ocket **W**eb **F**ramework **F**oundation, _RWF2_, is a
|
|
||||||
> <abbr title="RWF2 is granted 501(c)(3) status via its fiscal host, the OCF.">
|
|
||||||
> 501(c)(3) nonprofit</abbr> and <a href="https://opencollective.com/rwf2">
|
|
||||||
> collective</a> that supports the development and community of free and open
|
|
||||||
> source software, like <a href="https://rocket.rs">Rocket</a>, as well as
|
|
||||||
> education for a more secure web.
|
|
||||||
|
|
||||||
Moving forward, the RWF2 will be responsible for governing Rocket and dictating
|
|
||||||
its trajectory. The goal is to distribute control of the project and prohibit
|
|
||||||
one person from being able to stall its development. The RWF2 will also act as a
|
|
||||||
vehicle for tax-deductible contributions, funds management, and development
|
|
||||||
grant distribution, all with the aim of increasing high-quality contributions
|
|
||||||
and educational material.
|
|
||||||
|
|
||||||
In summary, the RWF2 exists to enable:
|
|
||||||
|
|
||||||
* **Diversified Leadership**
|
|
||||||
|
|
||||||
Key responsibilities, such as releases, security, infrastructure, and
|
|
||||||
community engagement will be distributed to community members under the
|
|
||||||
umbrella of the foundation.
|
|
||||||
|
|
||||||
* **Tax-Deductible Contributions**
|
|
||||||
|
|
||||||
Because the RWF2 is a 501(c)(3) organization, contributions are
|
|
||||||
tax-deductible. We particularly hope this encourages corporate sponsorship,
|
|
||||||
especially from those who depend on Rocket. As a nonprofit, the RWF2 must
|
|
||||||
transparently manage and disburse all funds.
|
|
||||||
|
|
||||||
* **Development Grants**
|
|
||||||
|
|
||||||
A key use for contributions is the foundation's sponsorship and
|
|
||||||
administration of µGrants: small (≤ $1k) grants for concrete work on
|
|
||||||
Rocket or related projects. Compensation is staged upon completion of
|
|
||||||
predefined milestones and quality requirements.
|
|
||||||
|
|
||||||
* **Increased Transparency**
|
|
||||||
|
|
||||||
Milestones, release schedules, and periodic updates form part of the
|
|
||||||
foundation's responsibilities. The aim is to keep the community informed on
|
|
||||||
Rocket's development and plans, making it easier to get and remain involved.
|
|
||||||
|
|
||||||
* **Educational Resource Expansion**
|
|
||||||
|
|
||||||
The RWF2 aims to enhance the accessibility of educational resources,
|
|
||||||
training, and mentorship for web application security, especially for
|
|
||||||
traditionally marginalized groups. Our focus lies in delivering
|
|
||||||
high-quality, practical materials for building secure web applications.
|
|
||||||
|
|
||||||
## What's Happening Now
|
|
||||||
|
|
||||||
There's a lot to do to realize these goals, but the process starts today. Here's
|
|
||||||
what's being done now:
|
|
||||||
|
|
||||||
0. **Open Sponsorship**
|
|
||||||
|
|
||||||
Starting now, you can sponsor the RWF2 through [GitHub Sponsors] or
|
|
||||||
[Open Collective]. Tiers are still a work in progress, but for now, consider
|
|
||||||
all tiers on Open Collective, and Bronze+ tiers on GitHub, as intended for
|
|
||||||
corporate sponsors. Note that only contributions made directly via Open
|
|
||||||
Collective are guaranteed to be tax-deductible.
|
|
||||||
|
|
||||||
A special shout out to `@martynp`, `@nathanielford`, and `@wezm` for
|
|
||||||
jumping the gun in the best of ways and sponsoring the RWF2 via GitHub
|
|
||||||
ahead of schedule. Thank you!
|
|
||||||
|
|
||||||
0. **Team Assembly**
|
|
||||||
|
|
||||||
Initially, RWF2 governance will be exceedingly simple and consist of a
|
|
||||||
president <small>(hi!)</small> and a handful of team leads. Individuals can
|
|
||||||
fill multiple positions, though the intent is for every position to be held
|
|
||||||
by a different individual. Positions are by appointment, either by the
|
|
||||||
presiding team lead, by the president in their absence, and by other team
|
|
||||||
leads in the president's absence.
|
|
||||||
|
|
||||||
The initial teams and their responsibilities are listed below. If you're
|
|
||||||
interested in leading any of the teams (or another team you think should
|
|
||||||
exist), please reach out via the [Matrix channel] or directly via
|
|
||||||
[foundation@rwf2.org](mailto:foundation@rwf2.org).
|
|
||||||
|
|
||||||
- *Maintenance*
|
|
||||||
|
|
||||||
Reviews issues, pull requests, and discussions, and acts on them as
|
|
||||||
necessary. This largely means triaging issues, closing resolved or
|
|
||||||
duplicate issues and discussions, closing or merging stale or approved
|
|
||||||
pull requests, respectively, and pinging the appropriate individuals to
|
|
||||||
prevent issues or PRs from becoming stale.
|
|
||||||
|
|
||||||
- *Release*
|
|
||||||
|
|
||||||
Publishes code and documentation releases. This includes partitioning
|
|
||||||
commits according to scope and impact on breakage, writing and updating
|
|
||||||
CHANGELOGs, and testing and publishing new releases and their
|
|
||||||
documentation.
|
|
||||||
|
|
||||||
- *Knowledge*
|
|
||||||
|
|
||||||
Creates, maintains and improves materials that help others learn about
|
|
||||||
Rocket or web security. This includes documentation like API docs and the
|
|
||||||
Rocket guide, code such as examples and tutorials, and materials for live
|
|
||||||
or in-person education.
|
|
||||||
|
|
||||||
- *Community*
|
|
||||||
|
|
||||||
Keeps the community adjourned on happenings. This involves writing
|
|
||||||
periodic project updates as well as digesting and communicating
|
|
||||||
development milestones and schedules to a broad audience.
|
|
||||||
|
|
||||||
- *Infrastructure*
|
|
||||||
|
|
||||||
Maintains infrastructure including: building, testing, and release
|
|
||||||
scripts, static site generation, CI and other automated processes, and
|
|
||||||
domain registrar and cloud computing services.
|
|
||||||
|
|
||||||
0. **Transfer of Assets**
|
|
||||||
|
|
||||||
The majority of Rocket's assets, including its domain, website, source
|
|
||||||
code, and associated infrastructure, are managed under personal accounts.
|
|
||||||
All assets are being transferred to foundation-owned accounts, and access
|
|
||||||
will be given to the appropriate teams. The [migration project on GitHub]
|
|
||||||
is tracking the progress of asset migration.
|
|
||||||
|
|
||||||
0. **Process Documentation**
|
|
||||||
|
|
||||||
Some of Rocket's core processes, including releases and site building, are
|
|
||||||
generally inaccessible to others. These will be documented, and access will
|
|
||||||
be granted to the appropriate teams.
|
|
||||||
|
|
||||||
0. **Open Planning & Development**
|
|
||||||
|
|
||||||
While Rocket's development has generally been done in the open through
|
|
||||||
GitHub issues, PRs, and projects, little has been done to publicize those
|
|
||||||
efforts. Furthermore, _planning_ has largely been a closed process. Moving
|
|
||||||
forward, planning will be done in the open, and the community team will be
|
|
||||||
engaged to publicize development efforts and progress.
|
|
||||||
|
|
||||||
[GitHub Sponsors]: https://github.com/sponsors/rwf2
|
|
||||||
[Open Collective]: https://opencollective.com/rwf2
|
|
||||||
[Matrix channel]: https://chat.mozilla.org/#/room/#rocket:mozilla.org
|
|
||||||
[migration project on GitHub]: https://github.com/orgs/rwf2/projects/1
|
|
||||||
|
|
||||||
## What's Coming Soon
|
|
||||||
|
|
||||||
* **µGrants**
|
|
||||||
|
|
||||||
The µGrant specification is a work-in-progress. We simulatenously want to
|
|
||||||
encourage and financially incentivize high-quality contributions while not
|
|
||||||
disincentivizing existing contributors. This is a delicate balance, and we
|
|
||||||
want to take the time to get it right. To get involved, see the current
|
|
||||||
[draft proposal](https://github.com/rwf2/rwf2.org/blob/master/docs/micro-grants.md) and
|
|
||||||
share your thoughts in the [GitHub discussion](https://github.com/orgs/rwf2/discussions/8).
|
|
||||||
As soon as we have a specification that feels fair, the first µGrants will
|
|
||||||
be offered.
|
|
||||||
|
|
||||||
* **Foundation Website**
|
|
||||||
|
|
||||||
The [RWF2 website](https://rwf2.org) as it stands is a placeholder for a
|
|
||||||
more fully featured website. Besides articulating the foundation's mission
|
|
||||||
and goals, the RWF2's website will also serve as a source of truth for the
|
|
||||||
status of and means to engaging with ongoing projects, grants, and finances.
|
|
||||||
|
|
||||||
* **Membership**
|
|
||||||
|
|
||||||
While certainly premature at this point in time, a consideration for the
|
|
||||||
future comes in the form of foundation _membership_ whereby governance is
|
|
||||||
expanded to include foundation _members_. The [governance proposal
|
|
||||||
document](https://github.com/rwf2/rwf2.org/blob/master/docs/governance.md)
|
|
||||||
has one take on how this might work. Until such a proposal is accepted,
|
|
||||||
governance will follow the president + teams model articulated above.
|
|
||||||
|
|
||||||
## How to Get Involved
|
|
||||||
|
|
||||||
The RWF2 represents a conscious effort to transfer control of Rocket from an
|
|
||||||
individual (me) to the community (you). Without your involvement, the RWF2
|
|
||||||
ceases to exist. If you're excited about Rocket or the foundation, or simply
|
|
||||||
want to see Rocket continue to exist and flourish, please get involved.
|
|
||||||
|
|
||||||
* **Join the Discussion**
|
|
||||||
|
|
||||||
Communicate with us via the [Matrix channel], via [GitHub
|
|
||||||
discussions](https://github.com/orgs/rwf2/discussions), or via email at
|
|
||||||
[foundation@rwf2.org](mailto:foundation@rwf2.org). The foundation bring-up
|
|
||||||
itself is designed to be collaborative, and any input you have is
|
|
||||||
invaluable.
|
|
||||||
|
|
||||||
* **Make a Contribution**
|
|
||||||
|
|
||||||
Any easy way to get involved is to financially contribute. You can sponsor
|
|
||||||
the RWF2 through [GitHub Sponsors] or [Open Collective]. If your company
|
|
||||||
uses Rocket, encourage it to sponsor the project through the foundation.
|
|
||||||
|
|
||||||
* **Become a Team Lead**
|
|
||||||
|
|
||||||
If you're interested in leading or learning more about any one of the
|
|
||||||
*Maintenance*, *Release*, *Knowledge*, *Community*, or *Infrastructure*
|
|
||||||
teams, or think another team should exist, please get in touch via the
|
|
||||||
[Matrix channel] or via email at [foundation@rwf2.org](mailto:foundation@rwf2.org).
|
|
||||||
|
|
||||||
I'm excited for this next step in Rocket's history, and I hope you'll join me in
|
|
||||||
making it a success.
|
|
|
@ -1,622 +0,0 @@
|
||||||
# Rocket v0.5: Stable, Async, Sentinels, Streams, SSE, Forms, WebSockets, & So Much More
|
|
||||||
|
|
||||||
<p class="metadata"><strong>
|
|
||||||
Posted by <a href="https://sergio.bz">Sergio Benitez</a> on Nov 17, 2023
|
|
||||||
</strong></p>
|
|
||||||
|
|
||||||
Four years, four release candidates, a thousand commits, and over a thousand
|
|
||||||
issues, discussions, and PRs later, I am ~~relieved~~ thrilled to announce the
|
|
||||||
general availability of Rocket v0.5.
|
|
||||||
|
|
||||||
> **Rocket** is an async backend web framework for Rust with a focus on
|
|
||||||
> usability, security, extensibility, and speed. Rocket makes it simple to write
|
|
||||||
> secure web applications without sacrificing productivity or performance.
|
|
||||||
|
|
||||||
We encourage all users to upgrade. For a guided migration from Rocket v0.4 to
|
|
||||||
Rocket v0.5, please consult the newly available [upgrading guide]. Rocket v0.4
|
|
||||||
will continue to be supported and receive security updates until the time Rocket
|
|
||||||
v0.6 is released.
|
|
||||||
|
|
||||||
! note: This is a co-announcement [along with the prelaunch] of [RWF2].
|
|
||||||
|
|
||||||
We're addressing the community's concerns regarding the pace of Rocket's
|
|
||||||
development, leadership, and release cadence in a separate announcement.
|
|
||||||
Please see the accompanying [RWF2 prelaunch announcement](../2023-11-17-rwf2-prelaunch/)
|
|
||||||
to learn more and see how you can get involved.
|
|
||||||
|
|
||||||
[RWF2]: https://rwf2.org
|
|
||||||
[along with the prelaunch]: ../2023-11-17-rwf2-prelaunch/
|
|
||||||
[upgrading guide]: @guide-v0.5/upgrading
|
|
||||||
|
|
||||||
## What's New?
|
|
||||||
|
|
||||||
Almost every bit has been reevaluated with a focus on usability and developer
|
|
||||||
productivity, security, and consistency across the library and [broader
|
|
||||||
ecosystem]. The changes are numerous, so we focus on the most noteworthy changes
|
|
||||||
here and encourage everyone to read the [CHANGELOG] for a complete list. For
|
|
||||||
answers to frequently asked questions, see the new [FAQ].
|
|
||||||
|
|
||||||
[CHANGELOG]: https://github.com/rwf2/Rocket/blob/v0.5.0/CHANGELOG.md
|
|
||||||
[broader ecosystem]: @guide-v0.5/faq/#releases
|
|
||||||
[FAQ]: @guide-v0.5/faq
|
|
||||||
|
|
||||||
### ⚓ Support for Stable `rustc` <badge>since `rc.1`</badge>
|
|
||||||
|
|
||||||
Rocket v0.5 compiles and builds on Rust stable. You can now compile and build
|
|
||||||
Rocket applications with `rustc` from the stable release channel and remove all
|
|
||||||
`#![feature(..)]` crate attributes. The complete canonical example with a single
|
|
||||||
`hello` route becomes:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[macro_use] extern crate rocket;
|
|
||||||
|
|
||||||
#[get("/<name>/<age>")]
|
|
||||||
fn hello(name: &str, age: u8) -> String {
|
|
||||||
format!("Hello, {} year old named {}!", age, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[launch]
|
|
||||||
fn rocket() -> _ {
|
|
||||||
rocket::build().mount("/hello", routes![hello])
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>See a <code>diff</code> of the changes from v0.4.</summary>
|
|
||||||
|
|
||||||
```diff
|
|
||||||
- #![feature(proc_macro_hygiene, decl_macro)]
|
|
||||||
-
|
|
||||||
#[macro_use] extern crate rocket;
|
|
||||||
|
|
||||||
#[get("/<name>/<age>")]
|
|
||||||
- fn hello(name: String, age: u8) -> String {
|
|
||||||
+ fn hello(name: &str, age: u8) -> String {
|
|
||||||
format!("Hello, {} year old named {}!", age, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
- fn main() {
|
|
||||||
- rocket::ignite().mount("/hello", routes![hello]).launch();
|
|
||||||
- }
|
|
||||||
+ #[launch]
|
|
||||||
+ fn rocket() -> _ {
|
|
||||||
+ rocket::build().mount("/hello", routes![hello])
|
|
||||||
+ }
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
Note the new [`launch`] attribute, which simplifies starting an `async` runtime
|
|
||||||
for Rocket applications. See the [migration guide] for more on transitioning to
|
|
||||||
a stable toolchain.
|
|
||||||
|
|
||||||
[`launch`]: @api-v0.5/rocket/attr.launch.html
|
|
||||||
|
|
||||||
### 📥 Async I/O <badge>since `rc.1`</badge>
|
|
||||||
|
|
||||||
Rocket's core request handling was rebuilt in v0.5 to take advantage of the
|
|
||||||
latest `async` networking facilities in Rust. Backed by `tokio`, Rocket
|
|
||||||
automatically multiplexes request handling across `async` tasks on all of the
|
|
||||||
available cores on the machine. As a result, route handlers can now be declared
|
|
||||||
`async` and make use of `await` syntax:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
use rocket::tokio;
|
|
||||||
use rocket::data::{Data, ToByteUnit};
|
|
||||||
|
|
||||||
#[post("/debug", data = "<data>")]
|
|
||||||
async fn debug(data: Data<'_>) -> std::io::Result<()> {
|
|
||||||
// Stream at most 512KiB all of the body data to stdout.
|
|
||||||
data.open(512.kibibytes())
|
|
||||||
.stream_to(tokio::io::stdout())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
See the [Blocking I/O](@guide-v0.5/upgrading#blocking-io) section of the upgrading
|
|
||||||
guide for complete details on the `async` I/O transition.
|
|
||||||
|
|
||||||
### 💂 Sentinels <badge>since `rc.1`</badge>
|
|
||||||
|
|
||||||
Rocket v0.5 introduces [sentinels]. Entirely unique to Rocket, sentinels offer
|
|
||||||
an automatic last line of defense against runtime errors by enabling any type
|
|
||||||
that appears in a route to abort application launch under invalid conditions.
|
|
||||||
For example, the [`&State<T>`] guard in v0.5 is a [`Sentinel`] that aborts
|
|
||||||
launch if the type `T` is not in managed state, thus preventing associated
|
|
||||||
runtime errors.
|
|
||||||
|
|
||||||
[`Sentinel`]s can be implemented outside of Rocket, too, and you should seek to
|
|
||||||
do so whenever possible. For instance, the [`Template`] type from
|
|
||||||
[`rocket_dyn_templates`] is a sentinel that ensures templates are properly
|
|
||||||
registered. As another example, consider a `MyResponder` that expects:
|
|
||||||
|
|
||||||
* A specific type `T` to be in managed state.
|
|
||||||
* An catcher to be registered for the `400` status code.
|
|
||||||
|
|
||||||
Making `MyResponder` a sentinel that guards against these conditions is as
|
|
||||||
simple as:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
use rocket::{Rocket, Ignite, Sentinel};
|
|
||||||
# struct MyResponder;
|
|
||||||
# struct T;
|
|
||||||
|
|
||||||
impl Sentinel for MyResponder {
|
|
||||||
fn abort(r: &Rocket<Ignite>) -> bool {
|
|
||||||
r.state::<T>().is_none() || !r.catchers().any(|c| c.code == Some(400))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[sentinels]: @api-v0.5/rocket/trait.Sentinel.html
|
|
||||||
[`Sentinel`]: @api-v0.5/rocket/trait.Sentinel.html
|
|
||||||
[`&State<T>`]: @api-v0.5/rocket/struct.State.html
|
|
||||||
[`Template`]: @api-v0.5/rocket_dyn_templates/struct.Template.html
|
|
||||||
[`rocket_dyn_templates`]: @api-v0.5/rocket_dyn_templates/index.html
|
|
||||||
|
|
||||||
### ☄️ Streams and SSE <badge>since `rc.1`</badge>
|
|
||||||
|
|
||||||
Powered by the new asynchronous core, Rocket v0.5 introduces real-time, typed
|
|
||||||
`async` [streams]. The new [async streams] section of the guide contains further
|
|
||||||
details, and we encourage all interested parties to see the new real-time,
|
|
||||||
multi-room [chat example].
|
|
||||||
|
|
||||||
As a taste of what's possible, the following `stream` route emits a `"pong"`
|
|
||||||
Server-Sent Event every `n` seconds, defaulting to `1`:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# use rocket::*;
|
|
||||||
use rocket::tokio::time::{interval, Duration};
|
|
||||||
use rocket::response::stream::{Event, EventStream};;
|
|
||||||
|
|
||||||
#[get("/ping?<n>")]
|
|
||||||
fn stream(n: Option<u64>) -> EventStream![] {
|
|
||||||
EventStream! {
|
|
||||||
let mut timer = interval(Duration::from_secs(n.unwrap_or(1)));
|
|
||||||
loop {
|
|
||||||
yield Event::data("pong");
|
|
||||||
timer.tick().await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[streams]: @api-v0.5/rocket/response/stream/index.html
|
|
||||||
[async streams]: @guide-v0.5/responses/#async-streams
|
|
||||||
[chat example]: @example/chat
|
|
||||||
|
|
||||||
### 🔌 WebSockets <badge>since `rc.4`</badge>
|
|
||||||
|
|
||||||
Rocket v0.5 introduces support for HTTP connection upgrades via a new [upgrade
|
|
||||||
API]. The API allows responders to assume control of raw I/O with the client in
|
|
||||||
an existing HTTP connection, thus allowing HTTP connections to be _upgraded_ to
|
|
||||||
any protocol, including WebSockets!
|
|
||||||
|
|
||||||
The newly introduced [`rocket_ws`] library takes advantage of the new API to
|
|
||||||
implement first-class support for WebSockets entirely outside of Rocket's core.
|
|
||||||
Working with `rocket_ws` to implement an echo server looks like this:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# use rocket::get;
|
|
||||||
use rocket_ws::{WebSocket, Stream};
|
|
||||||
|
|
||||||
#[get("/echo")]
|
|
||||||
fn echo_compose(ws: WebSocket) -> Stream!['static] {
|
|
||||||
ws.stream(|io| io)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Just like the newly introduced `async` streams, `rocket_ws` also supports using
|
|
||||||
generator syntax for WebSocket messages:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# use rocket::get;
|
|
||||||
use rocket_ws::{WebSocket, Stream};
|
|
||||||
|
|
||||||
#[get("/echo")]
|
|
||||||
fn echo_stream(ws: WebSocket) -> Stream!['static] {
|
|
||||||
Stream! { ws =>
|
|
||||||
for await message in ws {
|
|
||||||
yield message?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For complete usage details, see the [`rocket_ws`] documentation.
|
|
||||||
|
|
||||||
[upgrade API]: @api-v0.5/rocket/response/struct.Response.html#upgrading
|
|
||||||
[`rocket_ws`]: @api-v0.5/rocket_ws
|
|
||||||
|
|
||||||
### 📝 Comprehensive Forms <badge>since `rc.1`</badge>
|
|
||||||
|
|
||||||
Rocket v0.5 entirely revamps [forms] with support for [multipart uploads],
|
|
||||||
[arbitrary collections] with [arbitrary nesting], [ad-hoc validation], and an
|
|
||||||
improved [`FromForm` derive], obviating the need for nearly all custom
|
|
||||||
implementations of `FromForm` or `FromFormField`. Rocket's new wire protocol for
|
|
||||||
forms allows applications to express _any structure_ with _any level of nesting
|
|
||||||
and collection_ without any custom code, eclipsing what's offered by other web
|
|
||||||
frameworks.
|
|
||||||
|
|
||||||
As an illustrative example, consider the following structures:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
use rocket::form::FromForm;
|
|
||||||
|
|
||||||
#[derive(FromForm)]
|
|
||||||
struct MyForm<'r> {
|
|
||||||
owner: Person<'r>,
|
|
||||||
pet: Pet<'r>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromForm)]
|
|
||||||
struct Person<'r> {
|
|
||||||
name: &'r str
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromForm)]
|
|
||||||
struct Pet<'r> {
|
|
||||||
name: &'r str,
|
|
||||||
#[field(validate = eq(true))]
|
|
||||||
good_pet: bool,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To parse request data into a `MyForm`, a form with fields of `owner.name`,
|
|
||||||
`pet.name`, and `pet.good_pet` must be submitted. The ad-hoc validation on
|
|
||||||
`good_pet` validates that `good_pet` parses as `true`. Such a form, URL-encoded,
|
|
||||||
may look like:
|
|
||||||
|
|
||||||
```rust,ignore
|
|
||||||
"owner.name=Bob&pet.name=Sally&pet.good_pet=yes"
|
|
||||||
```
|
|
||||||
|
|
||||||
Rocket's derived `FromForm` implementation for `MyForm` will automatically parse
|
|
||||||
such a submission into the correct value:
|
|
||||||
|
|
||||||
```rust,ignore
|
|
||||||
MyForm {
|
|
||||||
owner: Person {
|
|
||||||
name: "Bob".into()
|
|
||||||
},
|
|
||||||
pet: Pet {
|
|
||||||
name: "Sally".into(),
|
|
||||||
good_pet: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# };
|
|
||||||
```
|
|
||||||
|
|
||||||
The rewritten [forms guide] provides complete details on revamped forms support.
|
|
||||||
|
|
||||||
[forms guide]: @guide-v0.5/requests/#forms
|
|
||||||
[ad-hoc validation]: @guide-v0.5/requests#ad-hoc-validation
|
|
||||||
[arbitrary nesting]: @guide-v0.5/requests#nesting
|
|
||||||
[multipart uploads]: @guide-v0.5/requests#multipart
|
|
||||||
[forms]: @guide-v0.5/requests#forms
|
|
||||||
[`FromFormField`]: @api-v0.5/rocket/form/trait.FromFormField.html
|
|
||||||
[arbitrary collections]: @guide-v0.5/requests#collections
|
|
||||||
[`FromForm` derive]: @api-v0.5/rocket/derive.FromForm.html
|
|
||||||
|
|
||||||
### 🚀 And so much more!
|
|
||||||
|
|
||||||
Rocket v0.5 introduces over **40** new features and major improvements! We
|
|
||||||
encourage everyone to review the [CHANGELOG] to learn about them all. Here are a
|
|
||||||
few more we don't want you to miss:
|
|
||||||
|
|
||||||
* An automatically enabled [`Shield`]: security and privacy headers for all responses.
|
|
||||||
* [Graceful shutdown] with configurable grace periods, [notification], and [shutdown fairings].
|
|
||||||
* An entirely new, flexible and robust [configuration system] based on [Figment].
|
|
||||||
* Type-system enforced [incoming data limits] to mitigate memory-based DoS attacks.
|
|
||||||
* Support for [mutual TLS] and client [`Certificate`]s.
|
|
||||||
* Asynchronous database pooling support via [`rocket_db_pools`].
|
|
||||||
* Compile-time URI literals via a fully revamped [`uri!`] macro.
|
|
||||||
|
|
||||||
[`Shield`]: @api-v0.5/rocket/shield/struct.Shield.html
|
|
||||||
[graceful shutdown]: @api-v0.5/rocket/config/struct.Shutdown.html#summary
|
|
||||||
[notification]: @api-v0.5/rocket/struct.Shutdown.html
|
|
||||||
[shutdown fairings]: @api-v0.5/rocket/fairing/trait.Fairing.html#shutdown
|
|
||||||
[configuration system]: @guide-v0.5/configuration/#configuration
|
|
||||||
[Figment]: https://docs.rs/figment/
|
|
||||||
[incoming data limits]: @guide-v0.5/requests/#streaming
|
|
||||||
[mutual TLS]: @guide-v0.5/configuration/#mutual-tls
|
|
||||||
[`uri!`]: @api-v0.5/rocket/macro.uri.html
|
|
||||||
[`rocket_db_pools`]: @api-v0.5/rocket_db_pools/index.html
|
|
||||||
[`Certificate`]: @api-v0.5/rocket/mtls/struct.Certificate.html
|
|
||||||
[migration guide]: @guide-v0.5/upgrading
|
|
||||||
|
|
||||||
## What's Next?
|
|
||||||
|
|
||||||
We think Rocket provides the most productive and confidence-inspiring web
|
|
||||||
development experience in Rust today, but as always, there's room for
|
|
||||||
improvement. To that end, here's what's on the docket for the next major
|
|
||||||
release:
|
|
||||||
|
|
||||||
0. **Migration to RWF2**
|
|
||||||
|
|
||||||
Discussed further in the [RWF2 prelaunch announcement], Rocket will
|
|
||||||
transition to being managed by the newly formed Rocket Web Framework
|
|
||||||
Foundation: _RWF2_. The net effect is increased development transparency,
|
|
||||||
including public roadmaps and periodic updates, financial support for
|
|
||||||
high-quality contributions, and codified pathways into the project's
|
|
||||||
governance.
|
|
||||||
|
|
||||||
0. **Pluggable Connection Listeners**
|
|
||||||
|
|
||||||
Rocket currently expects and enjoins connection origination via
|
|
||||||
TCP/IP. While sufficient for the common case, it excludes other desirable
|
|
||||||
interfaces such as Unix Domain Sockets (UDS).
|
|
||||||
|
|
||||||
In the next major release, Rocket will expose [an interface for implementing
|
|
||||||
and plugging-in custom connection listeners]. Rocket itself will make use
|
|
||||||
of this interface to expose more common mediums out-of-the-box, such as the
|
|
||||||
aforementioned UDS.
|
|
||||||
|
|
||||||
0. **Native `async` Traits**
|
|
||||||
|
|
||||||
Given the [stabilization of `async fn` in traits], the next major release
|
|
||||||
will seek to eliminate Rocket's dependence on `#[async_trait]` opting instead
|
|
||||||
for native `async` traits. This will greatly improve our documentation, which
|
|
||||||
currently calls out the attribute for each affected trait, as well as offer
|
|
||||||
modest performance improvements.
|
|
||||||
|
|
||||||
0. [**Typed Catchers**](https://github.com/rwf2/Rocket/issues/749)
|
|
||||||
|
|
||||||
Today's catchers cannot receive strictly typed error data. This results
|
|
||||||
in workarounds where error data is queried for well-typedness at runtime.
|
|
||||||
While it _has_ been possible to implement a form of typed error catching
|
|
||||||
prior, doing so necessitated limiting error data to `'static` values, as
|
|
||||||
other Rust web frameworks do, a concession we're unwilling to make.
|
|
||||||
|
|
||||||
After much experimentation, we have an approach that is ergonomic to use,
|
|
||||||
safe, and correct, all without the `'static` limitation. This will allow error
|
|
||||||
catchers to "pattern match" against error types at compile-time. At runtime,
|
|
||||||
Rocket will match emerging error types against the declared catchers and
|
|
||||||
call the appropriate catcher with the fully-typed value.
|
|
||||||
|
|
||||||
0. **Short-Circuitable Request Processing**
|
|
||||||
|
|
||||||
Whether with success or failure, fairings and guards cannot presently
|
|
||||||
terminate request processing early. The rationale for forbidding this
|
|
||||||
functionality was that it would allow third-party crates and plugins to
|
|
||||||
dictate responses without offering any recourse to the top-level application.
|
|
||||||
|
|
||||||
With the advent of typed catchers, however, we now have a mechanism by which
|
|
||||||
a top-level application can intercept early responses via their type,
|
|
||||||
resolving the prior concern. As such, in the next major release, fairings and
|
|
||||||
guards will be able to respond to requests early, and catchers will be able to
|
|
||||||
intercept those early responses at will.
|
|
||||||
|
|
||||||
0. **Associated Resources**
|
|
||||||
|
|
||||||
Often a set of routes will share a set requirements. For example, they
|
|
||||||
may share a URI prefix, subset of guards, and some managed state. In today's
|
|
||||||
Rocket, these common requirements must be repeatedly specified for each route.
|
|
||||||
While this is by design (we _want_ a route's requirements to be obvious), the
|
|
||||||
repetition is arduous and potentially error prone.
|
|
||||||
|
|
||||||
In an upcoming major release, Rocket will introduce new mechanisms by which
|
|
||||||
a set of routes can share an explicitly declared set of requirements. Their
|
|
||||||
_explicit_ and _declarative_ nature results in requirements that are
|
|
||||||
simultaneously obvious _and_ declared once.
|
|
||||||
|
|
||||||
We're really excited about this upcoming change and will be announcing more
|
|
||||||
in the near future.
|
|
||||||
|
|
||||||
0. **Performance Improvements**
|
|
||||||
|
|
||||||
Rocket appears to lag behind other Rust web frameworks in benchmarks. This is
|
|
||||||
partly due to [poor benchmarking], partly due to security-minded design
|
|
||||||
decisions, and partially due to unexploited opportunities. In the next
|
|
||||||
release, we'll be addressing the latter points. Specifically:
|
|
||||||
|
|
||||||
- _Explore making work stealing optional._
|
|
||||||
|
|
||||||
Rocket currently defaults to using tokio's multithreaded, work-stealing
|
|
||||||
scheduler. This avoids tail latency issues when faced with irregular and
|
|
||||||
heterogeneous tasks at the expense of throughput due to higher bookkeeping costs
|
|
||||||
associated with work stealing. Other Rust web frameworks instead opt to use
|
|
||||||
tokio's single-threaded scheduler, which while theoretically suboptimal,
|
|
||||||
may yield better performance results in practice, especially when
|
|
||||||
benchmarking homogeneous workloads.
|
|
||||||
|
|
||||||
While we believe work-stealing schedulers are the right choice for the
|
|
||||||
majority of applications desireing robust performance characteristics, we also
|
|
||||||
believe the choice should be the user's. We'll seek to make this choice
|
|
||||||
easier in the next release.
|
|
||||||
|
|
||||||
- _Reduce conversions from external to internal HTTP types._
|
|
||||||
|
|
||||||
Rocket revalidates and sometimes copies incoming HTTP request data.
|
|
||||||
In Rocket v0.5, we began transitioning to a model where we revalidate
|
|
||||||
security insensitive data in debug mode only, allowing for bugs to be
|
|
||||||
caught and reported while reducing performance impacts in production. In
|
|
||||||
the next release, we seek to extend this approach.
|
|
||||||
|
|
||||||
[an interface for implementing and plugging-in custom connection listeners]:
|
|
||||||
https://github.com/rwf2/Rocket/issues/1070#issuecomment-1491101952
|
|
||||||
[stabilization of `async fn` in traits]: https://github.com/rust-lang/rust/pull/115822
|
|
||||||
[poor benchmarking]: @guide-v0.5/faq/#performance
|
|
||||||
|
|
||||||
<!-- custom routers? -->
|
|
||||||
|
|
||||||
## ❤️ Thank You
|
|
||||||
|
|
||||||
A very special thank you to [Jeb Rosen], Rocket's maintainer from v0.4 to
|
|
||||||
v0.5-rc.1, without whom Rocket v0.5 wouldn't exist. Jeb is responsible for
|
|
||||||
leading the migration to `async` and Rust stable along with tireless efforts to
|
|
||||||
improve Rocket's documentation and address the community. Rocket is better for
|
|
||||||
having had Jeb along for the ride. Thank you, Jeb.
|
|
||||||
|
|
||||||
[Jeb Rosen]: https://github.com/rwf2/Rocket/commits?author=jebrosen
|
|
||||||
|
|
||||||
A special thank you to all of Rocket's users, especially those who diligently
|
|
||||||
waded through all four release candidates, raised issues, and participated on
|
|
||||||
[GitHub] and the [Matrix channel]. You all are an awesome, kind, and thoughtful
|
|
||||||
bunch. Thank you.
|
|
||||||
|
|
||||||
A heartfelt _thank you_ as well to _all_ **148** who contributed to Rocket v0.5:
|
|
||||||
|
|
||||||
<ul class="columns">
|
|
||||||
<li>Aaron Leopold</li>
|
|
||||||
<li>Abdullah Alyan</li>
|
|
||||||
<li>Aditya</li>
|
|
||||||
<li>Alex Macleod</li>
|
|
||||||
<li>Alex Sears</li>
|
|
||||||
<li>Alexander van Ratingen</li>
|
|
||||||
<li>ami-GS</li>
|
|
||||||
<li>Antoine Martin</li>
|
|
||||||
<li>arctic-alpaca</li>
|
|
||||||
<li>arlecchino</li>
|
|
||||||
<li>Arthur Woimbée</li>
|
|
||||||
<li>atouchet</li>
|
|
||||||
<li>Aurora</li>
|
|
||||||
<li>badoken</li>
|
|
||||||
<li>Beep LIN</li>
|
|
||||||
<li>Ben Sully</li>
|
|
||||||
<li>Benedikt Weber</li>
|
|
||||||
<li>Benjamin B</li>
|
|
||||||
<li>BlackDex</li>
|
|
||||||
<li>Bonex</li>
|
|
||||||
<li>Brenden Matthews</li>
|
|
||||||
<li>Brendon Federko</li>
|
|
||||||
<li>Brett Buford</li>
|
|
||||||
<li>Cedric Hutchings</li>
|
|
||||||
<li>Cezar Halmagean</li>
|
|
||||||
<li>Charles-Axel Dein</li>
|
|
||||||
<li>Compro Prasad</li>
|
|
||||||
<li>cui fliter</li>
|
|
||||||
<li>Daniel Wiesenberg</li>
|
|
||||||
<li>David Venhoek</li>
|
|
||||||
<li>Dimitri Sabadie</li>
|
|
||||||
<li>Dinu Blanovschi</li>
|
|
||||||
<li>Dominik Boehi</li>
|
|
||||||
<li>Doni Rubiagatra</li>
|
|
||||||
<li>Edgar Onghena</li>
|
|
||||||
<li>Edwin Svensson</li>
|
|
||||||
<li>est31</li>
|
|
||||||
<li>Felix Suominen</li>
|
|
||||||
<li>Fenhl</li>
|
|
||||||
<li>Filip Gospodinov</li>
|
|
||||||
<li>Flying-Toast</li>
|
|
||||||
<li>Follpvosten</li>
|
|
||||||
<li>Francois Stephany</li>
|
|
||||||
<li>Gabriel Fontes</li>
|
|
||||||
<li>gcarq</li>
|
|
||||||
<li>George Cheng</li>
|
|
||||||
<li>Giles Cope</li>
|
|
||||||
<li>Gonçalo Ribeiro</li>
|
|
||||||
<li>hiyoko3m</li>
|
|
||||||
<li>Howard Su</li>
|
|
||||||
<li>hpodhaisky</li>
|
|
||||||
<li>Ian Jackson</li>
|
|
||||||
<li>IFcoltransG</li>
|
|
||||||
<li>Indosaram</li>
|
|
||||||
<li>inyourface34456</li>
|
|
||||||
<li>J. Cohen</li>
|
|
||||||
<li>Jacob Pratt</li>
|
|
||||||
<li>Jacob Sharf</li>
|
|
||||||
<li>Jacob Simpson</li>
|
|
||||||
<li>Jakub Dąbek</li>
|
|
||||||
<li>Jakub Wieczorek</li>
|
|
||||||
<li>James Tai</li>
|
|
||||||
<li>Jason Hinch</li>
|
|
||||||
<li>Jeb Rosen</li>
|
|
||||||
<li>Jeremy Kaplan</li>
|
|
||||||
<li>Jieyou Xu</li>
|
|
||||||
<li>Joakim Soderlund</li>
|
|
||||||
<li>Johannes Liebermann</li>
|
|
||||||
<li>John-John Tedro</li>
|
|
||||||
<li>Jonah Brüchert</li>
|
|
||||||
<li>Jonas Møller</li>
|
|
||||||
<li>Jonathan Dickinson</li>
|
|
||||||
<li>Jonty</li>
|
|
||||||
<li>Joscha</li>
|
|
||||||
<li>Joshua Nitschke</li>
|
|
||||||
<li>JR Heard</li>
|
|
||||||
<li>Juhasz Sandor</li>
|
|
||||||
<li>Julian Büttner</li>
|
|
||||||
<li>Juraj Fiala</li>
|
|
||||||
<li>Kenneth Allen</li>
|
|
||||||
<li>Kevin Wang</li>
|
|
||||||
<li>Kian-Meng Ang</li>
|
|
||||||
<li>Konrad Borowski</li>
|
|
||||||
<li>Leonora Tindall</li>
|
|
||||||
<li>Lev Kokotov</li>
|
|
||||||
<li>lewis</li>
|
|
||||||
<li>Lionel G</li>
|
|
||||||
<li>Lucille Blumire</li>
|
|
||||||
<li>Mai-Lapyst</li>
|
|
||||||
<li>Manuel</li>
|
|
||||||
<li>Manuel Transfeld</li>
|
|
||||||
<li>Marc Schreiber</li>
|
|
||||||
<li>Marc-Stefan Cassola</li>
|
|
||||||
<li>Marshall Bowers</li>
|
|
||||||
<li>Martin1887</li>
|
|
||||||
<li>Martinez</li>
|
|
||||||
<li>Matthew Pomes</li>
|
|
||||||
<li>Maxime Guerreiro</li>
|
|
||||||
<li>meltinglava</li>
|
|
||||||
<li>Michael Howell</li>
|
|
||||||
<li>Mikail Bagishov</li>
|
|
||||||
<li>mixio</li>
|
|
||||||
<li>multisn8</li>
|
|
||||||
<li>Necmettin Karakaya</li>
|
|
||||||
<li>Ning Sun</li>
|
|
||||||
<li>Nya</li>
|
|
||||||
<li>Paolo Barbolini</li>
|
|
||||||
<li>Paul Smith</li>
|
|
||||||
<li>Paul van Tilburg</li>
|
|
||||||
<li>Paul Weaver</li>
|
|
||||||
<li>pennae</li>
|
|
||||||
<li>Petr Portnov</li>
|
|
||||||
<li>philipp</li>
|
|
||||||
<li>Pieter Frenssen</li>
|
|
||||||
<li>PROgrm_JARvis</li>
|
|
||||||
<li>Razican</li>
|
|
||||||
<li>Redrield</li>
|
|
||||||
<li>Riley Patterson</li>
|
|
||||||
<li>Rodolphe Bréard</li>
|
|
||||||
<li>Roger Mo</li>
|
|
||||||
<li>RotesWasser</li>
|
|
||||||
<li>rotoclone</li>
|
|
||||||
<li>Ruben Schmidmeister</li>
|
|
||||||
<li>Rudi Floren</li>
|
|
||||||
<li>Rémi Lauzier</li>
|
|
||||||
<li>Samuele Esposito</li>
|
|
||||||
<li>Scott McMurray</li>
|
|
||||||
<li>Sergio Benitez</li>
|
|
||||||
<li>Silas Sewell</li>
|
|
||||||
<li>Soham Roy</li>
|
|
||||||
<li>Steven Murdoch</li>
|
|
||||||
<li>Stuart Hinson</li>
|
|
||||||
<li>Thibaud Martinez</li>
|
|
||||||
<li>Thomas Eckert</li>
|
|
||||||
<li>ThouCheese</li>
|
|
||||||
<li>Tilen Pintarič</li>
|
|
||||||
<li>timando</li>
|
|
||||||
<li>timokoesters</li>
|
|
||||||
<li>toshokan</li>
|
|
||||||
<li>TotalKrill</li>
|
|
||||||
<li>Unpublished</li>
|
|
||||||
<li>Vasili</li>
|
|
||||||
<li>Vladimir Ignatev</li>
|
|
||||||
<li>Wesley Norris</li>
|
|
||||||
<li>xelivous</li>
|
|
||||||
<li>YetAnotherMinion</li>
|
|
||||||
<li>Yohannes Kifle</li>
|
|
||||||
<li>Yusuke Kominami</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
[GitHub discussions]: https://github.com/rwf2/Rocket/discussions
|
|
||||||
[Matrix channel]: https://chat.mozilla.org/#/room/#rocket:mozilla.org
|
|
||||||
|
|
||||||
## Get Involved
|
|
||||||
|
|
||||||
Looking to help with Rocket? To contribute code, head over to [GitHub]. To get
|
|
||||||
involved with the project, see the [RWF2 prelaunch announcement]. We'd love to have you.
|
|
||||||
|
|
||||||
[GitHub]: https://github.com/rwf2/Rocket
|
|
||||||
[RWF2 prelaunch announcement]: ../2023-11-17-rwf2-prelaunch/
|
|
|
@ -1,180 +0,0 @@
|
||||||
[[articles]]
|
|
||||||
title = """
|
|
||||||
Rocket v0.5: Stable, Async, Feature-Packed
|
|
||||||
"""
|
|
||||||
slug = "2023-11-17-version-0.5"
|
|
||||||
author = "Sergio Benitez"
|
|
||||||
author_url = "https://sergio.bz"
|
|
||||||
date = "Nov 17, 2023"
|
|
||||||
snippet = """
|
|
||||||
I am _elated_ to announce that Rocket v0.5 is now generally available. A step
|
|
||||||
forward in every direction, it is **packed** with features and improvements that
|
|
||||||
increase developer productivity, improve application security and robustness,
|
|
||||||
provide new opportunities for extensibility, and afford toolchain stability.
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[articles]]
|
|
||||||
title = """
|
|
||||||
Building a Better Foundation for Rocket's Future
|
|
||||||
"""
|
|
||||||
slug = "2023-11-17-rwf2-prelaunch"
|
|
||||||
author = "Sergio Benitez"
|
|
||||||
author_url = "https://sergio.bz"
|
|
||||||
date = "Nov 17, 2023"
|
|
||||||
snippet = """
|
|
||||||
Today I'm excited to share plans to launch the Rocket Web Framework Foundation
|
|
||||||
(RWF2), a 501(c)(3) nonprofit and collective to support Rocket and the
|
|
||||||
surrounding ecosystem.
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[articles]]
|
|
||||||
title = """
|
|
||||||
Rocket's 4th v0.5 Release Candidate
|
|
||||||
"""
|
|
||||||
slug = "2023-11-01-version-0.5-rc.4"
|
|
||||||
author = "Sergio Benitez"
|
|
||||||
author_url = "https://sergio.bz"
|
|
||||||
date = "November 01, 2023"
|
|
||||||
snippet = """
|
|
||||||
Rocket `0.5.0-rc.4`, a release candidate for Rocket v0.5, is now available.
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[articles]]
|
|
||||||
title = """
|
|
||||||
Rocket's 3rd v0.5 Release Candidate
|
|
||||||
"""
|
|
||||||
slug = "2023-03-23-version-0.5-rc.3"
|
|
||||||
author = "Sergio Benitez"
|
|
||||||
author_url = "https://sergio.bz"
|
|
||||||
date = "March 23, 2023"
|
|
||||||
snippet = """
|
|
||||||
Rocket `0.5.0-rc.3`, a release candidate for Rocket v0.5, is now available.
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[articles]]
|
|
||||||
title = """
|
|
||||||
Rocket's 2nd v0.5 Release Candidate
|
|
||||||
"""
|
|
||||||
slug = "2022-05-09-version-0.5-rc.2"
|
|
||||||
author = "Sergio Benitez"
|
|
||||||
author_url = "https://sergio.bz"
|
|
||||||
date = "May 09, 2022"
|
|
||||||
snippet = """
|
|
||||||
Rocket `0.5.0-rc.2`, a release candidate for Rocket v0.5, is now available.
|
|
||||||
|
|
||||||
This release builds on the previous release candidate and brings further
|
|
||||||
features, improvements, and fixes to Rocket. As before, this is an opportunity
|
|
||||||
to discover issues with Rocket v0.5 and its documentation before its general
|
|
||||||
release.
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[articles]]
|
|
||||||
title = """
|
|
||||||
Rocket v0.5 Release Candidate
|
|
||||||
"""
|
|
||||||
slug = "2021-06-09-version-0.5-rc.1"
|
|
||||||
author = "Sergio Benitez"
|
|
||||||
author_url = "https://sergio.bz"
|
|
||||||
date = "June 09, 2021"
|
|
||||||
snippet = """
|
|
||||||
Rocket `0.5.0-rc.1`, a release candidate for Rocket v0.5, is now available.
|
|
||||||
|
|
||||||
This release actualizes over _two years_ of development, bringing Rocket to Rust
|
|
||||||
stable and `async` to Rocket. Every facet, from core request handling to error
|
|
||||||
messages, has been subjected to Rocket's exacting standards.
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[articles]]
|
|
||||||
title = """
|
|
||||||
Rocket v0.4: Typed URIs, Database Support, Revamped Queries, & More!
|
|
||||||
"""
|
|
||||||
slug = "2018-12-08-version-0.4"
|
|
||||||
author = "Sergio Benitez"
|
|
||||||
author_url = "https://sergio.bz"
|
|
||||||
date = "December 08, 2018"
|
|
||||||
snippet = """
|
|
||||||
I am elated to announce that the next major release of Rocket is now available!
|
|
||||||
Rocket 0.4 is a step forward in every direction: it is **packed** with features
|
|
||||||
and improvements that increase developer productivity, improve application
|
|
||||||
security and robustness, provide new opportunities for extensibility, and
|
|
||||||
deliver a renewed degree of toolchain stability.
|
|
||||||
|
|
||||||
Rocket 0.4 is the culmination of more than a year of development. During this
|
|
||||||
time, more than 600 changes were committed, almost 400 issues were closed, and
|
|
||||||
over 165 pull requests were submitted. The Rocket community has proved steadfast
|
|
||||||
in its support: a sincere thank you to everyone involved!
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[articles]]
|
|
||||||
title = "Rocket's 2nd v0.4 Release Candidate"
|
|
||||||
slug = "2018-11-30-version-0.4-rc-2"
|
|
||||||
author = "Sergio Benitez"
|
|
||||||
author_url = "https://sergio.bz"
|
|
||||||
date = "November 30, 2018"
|
|
||||||
snippet = """
|
|
||||||
After a successful and productive initial v0.4 release candidate, I am happy to
|
|
||||||
announce that the second release candidate for Rocket v0.4 is now available.
|
|
||||||
|
|
||||||
This release candidate fixes issues identified during the first release
|
|
||||||
candidate, introduces further features, and leverages upstream `rustc`
|
|
||||||
contributions for improved diagnostics and stability. As before, this is an
|
|
||||||
opportunity to discover issues with Rocket v0.4 and its documentation before its
|
|
||||||
general release. We encourage all users to migrate their applications to the
|
|
||||||
second release candidate and report any issues to the [GitHub issue tracker].
|
|
||||||
|
|
||||||
[GitHub issue tracker]: https://github.com/rwf2/Rocket/issues
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[articles]]
|
|
||||||
title = "Rocket v0.4 Release Candidate"
|
|
||||||
slug = "2018-10-31-version-0.4-rc"
|
|
||||||
author = "Sergio Benitez"
|
|
||||||
author_url = "https://sergio.bz"
|
|
||||||
date = "October 31, 2018"
|
|
||||||
snippet = """
|
|
||||||
I am delighted to announce that a release candidate for Rocket v0.4 is available
|
|
||||||
today! This release brings over a year of features, improvements, and
|
|
||||||
refinements, resolving some of the most called for requests and bringing Rocket
|
|
||||||
measurably closer to stable compatibility.
|
|
||||||
|
|
||||||
The release candidate is an opportunity to discover issues with Rocket v0.4 and
|
|
||||||
its documentation before its general release. We encourage all users to migrate
|
|
||||||
their applications to the release candidate and report any issues to the [GitHub
|
|
||||||
issue tracker].
|
|
||||||
|
|
||||||
[GitHub issue tracker]: https://github.com/rwf2/Rocket/issues
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[articles]]
|
|
||||||
title = "Rocket v0.3: Fairings, TLS, Private Cookies"
|
|
||||||
slug = "2017-07-14-version-0.3"
|
|
||||||
author = "Sergio Benitez"
|
|
||||||
author_url = "https://sergio.bz"
|
|
||||||
date = "July 14, 2017"
|
|
||||||
snippet = """
|
|
||||||
I'm excited to announce that the next major release of Rocket is available
|
|
||||||
today! Rocket 0.3 is packed with new features and improvements that increase
|
|
||||||
developer productivity, improve application security, and provide new
|
|
||||||
opportunities for extensibility. Rocket 0.3 is the culmination of almost 6
|
|
||||||
months of work. During this time, more than 225 changes were committed, over 100
|
|
||||||
issues (primarily questions and feature requests) were closed, and over 40 pull
|
|
||||||
requests were submitted. The Rocket community has proven steadfast in their
|
|
||||||
support: a sincere thank you to everyone involved!
|
|
||||||
"""
|
|
||||||
|
|
||||||
[[articles]]
|
|
||||||
title = "Rocket v0.2: Managed State & More"
|
|
||||||
slug = "2017-02-06-version-0.2"
|
|
||||||
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
|
|
||||||
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/rwf2/Rocket/issues)
|
|
||||||
or via direct contributions. In fact, there have been **20 unique contributors**
|
|
||||||
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.
|
|
||||||
"""
|
|
|
@ -1,69 +0,0 @@
|
||||||
###############################################################################
|
|
||||||
# Steps to "How Rocket Works"
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
[[steps]]
|
|
||||||
name = "Validation"
|
|
||||||
color = "blue"
|
|
||||||
content = '''
|
|
||||||
First, Rocket validates a matching request by ensuring that all of the types in
|
|
||||||
a given handler can be derived from the incoming request. If the types cannot be
|
|
||||||
derived, the request is forwarded to the next matching route until a route’s
|
|
||||||
types validate or there are no more routes to try. If all routes fail, a
|
|
||||||
customizable **404** error is returned.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[post("/user", data = "<new_user>")]
|
|
||||||
fn new_user(admin: AdminUser, new_user: Form<User>) -> T {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For the `new_user` handler above to be called, the following conditions must
|
|
||||||
hold:
|
|
||||||
|
|
||||||
* The request method must be `POST`.
|
|
||||||
* The request path must be `/user`.
|
|
||||||
* The request must contain `data` in its body.
|
|
||||||
* The request metadata must authenticate an `AdminUser`.
|
|
||||||
* The request body must be a form that parses into a `User` struct.
|
|
||||||
'''
|
|
||||||
|
|
||||||
[[steps]]
|
|
||||||
name = "Processing"
|
|
||||||
color = "purple"
|
|
||||||
content = '''
|
|
||||||
Next, the request is processed by an arbitrary handler. This is where most of
|
|
||||||
the business logic in an application resides, and the part of your applications
|
|
||||||
you’ll likely spend the most time writing. In Rocket, handlers are simply
|
|
||||||
functions - that’s it! The only caveat is that the function’s return type must
|
|
||||||
implement the `Responder` trait. The `new_user` function above is an example of
|
|
||||||
a handler.
|
|
||||||
'''
|
|
||||||
|
|
||||||
[[steps]]
|
|
||||||
name = "Response"
|
|
||||||
color = "red"
|
|
||||||
content = '''
|
|
||||||
Finally, Rocket responds to the client by transforming the return value of the
|
|
||||||
handler into an HTTP response. The HTTP response generated from the returned
|
|
||||||
value depends on the type’s specific `Responder` trait implementation.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
fn route() -> T { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
If the function above is used as a handler, for instance, then the type `T` must
|
|
||||||
implement `Responder`. Rocket provides many useful responder types out of the
|
|
||||||
box. They include:
|
|
||||||
|
|
||||||
* `Json<T>`: Serializes the structure T into JSON and returns it to
|
|
||||||
the client.
|
|
||||||
* `Template`: Renders a template file and returns it to the client.
|
|
||||||
* `Redirect`: Returns a properly formatted HTTP redirect.
|
|
||||||
* `NamedFile`: Streams a given file to the client with the
|
|
||||||
Content-Type taken from the file’s extension.
|
|
||||||
* `Stream`: Streams data to the client from an arbitrary `Read` value.
|
|
||||||
* Many Primitive Types: `String`, `&str`, `File`, `Option`, `Result`, and
|
|
||||||
others all implement the `Responder` trait.
|
|
||||||
'''
|
|
Loading…
Reference in New Issue