2017-04-17 02:48:59 +00:00
|
|
|
# Overview
|
|
|
|
|
2018-10-22 21:47:35 +00:00
|
|
|
Rocket provides primitives to build web servers and applications with Rust:
|
|
|
|
Rocket provides routing, pre-processing of requests, and post-processing of
|
|
|
|
responses; the rest is up to you. Your application code instructs Rocket on what
|
|
|
|
to pre-process and post-process and fills the gaps between pre-processing and
|
|
|
|
post-processing.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
## Lifecycle
|
|
|
|
|
|
|
|
Rocket's main task is to listen for incoming web requests, dispatch the request
|
|
|
|
to the application code, and return a response to the client. We call the
|
2017-07-03 05:51:24 +00:00
|
|
|
process that goes from request to response the "lifecycle". We summarize the
|
|
|
|
lifecycle as the following sequence of steps:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
1. **Routing**
|
|
|
|
|
2017-07-03 05:51:24 +00:00
|
|
|
Rocket parses an incoming HTTP request into native structures that your
|
|
|
|
code operates on indirectly. Rocket determines which request handler to
|
|
|
|
invoke by matching against route attributes declared in your application.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
2. **Validation**
|
|
|
|
|
2017-07-03 05:51:24 +00:00
|
|
|
Rocket validates the incoming request against types and guards present in
|
|
|
|
the matched route. If validation fails, Rocket _forwards_ the request to
|
|
|
|
the next matching route or calls an _error handler_.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
3. **Processing**
|
|
|
|
|
2017-07-03 05:51:24 +00:00
|
|
|
The request handler associated with the route is invoked with validated
|
|
|
|
arguments. This is the main business logic of an application. Processing
|
|
|
|
completes by returning a `Response`.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
4. **Response**
|
|
|
|
|
2017-07-03 05:51:24 +00:00
|
|
|
The returned `Response` is processed. Rocket generates the appropriate HTTP
|
|
|
|
response and sends it to the client. This completes the lifecycle. Rocket
|
|
|
|
continues listening for requests, restarting the lifecycle for each
|
|
|
|
incoming request.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
The remainder of this section details the _routing_ phase as well as additional
|
|
|
|
components needed for Rocket to begin dispatching requests to request handlers.
|
2017-07-10 11:59:55 +00:00
|
|
|
The sections following describe the request and response phases as well as other
|
|
|
|
components of Rocket.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
## Routing
|
|
|
|
|
2017-07-03 05:51:24 +00:00
|
|
|
Rocket applications are centered around routes and handlers. A _route_ is a
|
|
|
|
combination of:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
* A set of parameters to match an incoming request against.
|
|
|
|
* A handler to process the request and return a response.
|
|
|
|
|
2017-07-03 05:51:24 +00:00
|
|
|
A _handler_ is simply a function that takes an arbitrary number of arguments and
|
|
|
|
returns any arbitrary type.
|
|
|
|
|
2017-04-17 02:48:59 +00:00
|
|
|
The parameters to match against include static paths, dynamic paths, path
|
|
|
|
segments, forms, query strings, request format specifiers, and body data. Rocket
|
|
|
|
uses attributes, which look like function decorators in other languages, to make
|
|
|
|
declaring routes easy. Routes are declared by annotating a function, the
|
|
|
|
handler, with the set of parameters to match against. A complete route
|
|
|
|
declaration looks like this:
|
|
|
|
|
|
|
|
```rust
|
2020-02-15 11:43:47 +00:00
|
|
|
# #[macro_use] extern crate rocket;
|
|
|
|
|
2017-04-17 02:48:59 +00:00
|
|
|
#[get("/world")] // <- route attribute
|
|
|
|
fn world() -> &'static str { // <- request handler
|
2020-02-15 11:43:47 +00:00
|
|
|
"hello, world!"
|
2017-04-17 02:48:59 +00:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
This declares the `world` route to match against the static path `"/world"` on
|
2020-06-12 03:41:10 +00:00
|
|
|
incoming `GET` requests. Instead of `#[get]`, we could have used `#[post]` or
|
|
|
|
`#[put]` for other HTTP methods, or `#[catch]` for serving [custom error
|
|
|
|
pages](../requests/#error-catchers). Additionally, other route parameters may be
|
|
|
|
necessary when building more interesting applications. The
|
|
|
|
[Requests](../requests) chapter, which follows this one, has further details on
|
|
|
|
routing and error handling.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2020-07-22 19:44:13 +00:00
|
|
|
! note: We prefer `#[macro_use]`, but you may prefer explicit imports.
|
|
|
|
|
|
|
|
Throughout this guide and the majority of Rocket's documentation, we import
|
|
|
|
`rocket` explicitly with `#[macro_use]` even though the Rust 2018 edition
|
|
|
|
makes explicitly importing crates optional. However, explicitly importing with
|
|
|
|
`#[macro_use]` imports macros globally, allowing you to use Rocket's macros
|
|
|
|
anywhere in your application without importing them explicitly.
|
|
|
|
|
|
|
|
You may instead prefer to import macros explicitly or refer to them with
|
2021-04-08 02:01:48 +00:00
|
|
|
absolute paths: `use rocket::get;` or `#[rocket::get]`.
|
2020-07-22 19:44:13 +00:00
|
|
|
|
2017-04-17 02:48:59 +00:00
|
|
|
## Mounting
|
|
|
|
|
2018-10-22 21:47:35 +00:00
|
|
|
Before Rocket can dispatch requests to a route, the route needs to be _mounted_:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
```rust
|
2020-02-15 11:43:47 +00:00
|
|
|
# #[macro_use] extern crate rocket;
|
|
|
|
|
|
|
|
# #[get("/world")]
|
|
|
|
# fn world() -> &'static str {
|
|
|
|
# "hello, world!"
|
|
|
|
# }
|
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
rocket::ignite().mount("/hello", routes![world]);
|
2017-04-17 02:48:59 +00:00
|
|
|
```
|
|
|
|
|
2018-10-22 21:47:35 +00:00
|
|
|
The `mount` method takes as input:
|
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
1. A _base_ path to namespace a list of routes under, here, `/hello`.
|
2019-05-11 02:39:38 +00:00
|
|
|
2. A list of routes via the `routes!` macro: here, `routes![world]`, with
|
|
|
|
multiple routes: `routes![a, b, c]`.
|
2018-10-22 21:47:35 +00:00
|
|
|
|
2017-07-03 05:51:24 +00:00
|
|
|
This creates a new `Rocket` instance via the `ignite` function and mounts the
|
2020-11-03 20:50:31 +00:00
|
|
|
`world` route to the `/hello` base path, making Rocket aware of the route.
|
|
|
|
`GET` requests to `/hello/world` will be directed to the `world` function.
|
|
|
|
|
|
|
|
The `mount` method, like all other builder methods on `Rocket`, can be chained
|
|
|
|
any number of times, and routes can be reused by mount points:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
# #[macro_use] extern crate rocket;
|
|
|
|
|
|
|
|
# #[get("/world")]
|
|
|
|
# fn world() -> &'static str {
|
|
|
|
# "hello, world!"
|
|
|
|
# }
|
|
|
|
|
|
|
|
rocket::ignite()
|
|
|
|
.mount("/hello", routes![world])
|
|
|
|
.mount("/hi", routes![world]);
|
|
|
|
```
|
|
|
|
|
|
|
|
By mounting `world` to both `/hello` and `/hi`, requests to `"/hello/world"`
|
|
|
|
_and_ `"/hi/world"` will be directed to the `world` function.
|
2018-10-22 21:47:35 +00:00
|
|
|
|
|
|
|
! note: In many cases, the base path will simply be `"/"`.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
## Launching
|
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
Rocket begins serving requests after being _launched_, which starts a
|
|
|
|
multi-threaded asynchronous server and dispatches requests to matching routes as
|
|
|
|
they arrive.
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
There are two mechnisms by which a `Rocket` can be launched. The first and
|
|
|
|
preferred approach is via the `#[launch]` route attribute, which generates a
|
|
|
|
`main` function that sets up an async runtime and starts the server. With
|
|
|
|
`#[launch]`, our complete _Hello, world!_ application looks like:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
```rust
|
2018-10-05 04:44:42 +00:00
|
|
|
#[macro_use] extern crate rocket;
|
2017-04-17 02:48:59 +00:00
|
|
|
|
|
|
|
#[get("/world")]
|
|
|
|
fn world() -> &'static str {
|
|
|
|
"Hello, world!"
|
|
|
|
}
|
|
|
|
|
2020-07-22 23:10:02 +00:00
|
|
|
#[launch]
|
2020-07-11 16:42:05 +00:00
|
|
|
fn rocket() -> rocket::Rocket {
|
|
|
|
rocket::ignite().mount("/hello", routes![world])
|
2017-04-17 02:48:59 +00:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Running the application, the console shows:
|
|
|
|
|
|
|
|
```sh
|
2020-11-03 20:50:31 +00:00
|
|
|
> cargo run
|
|
|
|
🔧 Configured for debug.
|
|
|
|
=> address: 127.0.0.1
|
2017-04-17 02:48:59 +00:00
|
|
|
=> port: 8000
|
2020-11-03 20:50:31 +00:00
|
|
|
=> workers: 64
|
|
|
|
=> log level: normal
|
|
|
|
=> secret key: [zero]
|
2017-07-03 05:51:24 +00:00
|
|
|
=> limits: forms = 32KiB
|
2020-11-03 20:50:31 +00:00
|
|
|
=> cli colors: true
|
2018-10-22 21:47:35 +00:00
|
|
|
=> keep-alive: 5s
|
2017-07-03 05:51:24 +00:00
|
|
|
=> tls: disabled
|
2020-11-03 20:56:20 +00:00
|
|
|
🛰 Mounting /hello:
|
|
|
|
=> GET /hello/world (world)
|
2020-11-03 20:50:31 +00:00
|
|
|
🚀 Rocket has launched from http://127.0.0.1:8000
|
2017-04-17 02:48:59 +00:00
|
|
|
```
|
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
! tip: You can also return `_` from a `#[launch]` function!
|
|
|
|
|
|
|
|
If you find it more pleasing, `#[launch]` can infer the return type of
|
|
|
|
`Rocket` for you by using `_` as the return type:
|
2017-04-17 02:48:59 +00:00
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
`
|
|
|
|
#[launch] fn rocket() -> _ { /* ... */ }
|
|
|
|
`
|
|
|
|
|
|
|
|
If we visit `http://127.0.0.1:8000/hello/world`, we see `Hello, world!`, exactly
|
|
|
|
as we expected.
|
|
|
|
|
|
|
|
! note: This and other examples are on GitHub.
|
|
|
|
|
2021-04-08 02:01:48 +00:00
|
|
|
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
|
|
|
|
complete examples, spanning all of Rocket's features, in the [GitHub examples
|
2020-11-03 20:50:31 +00:00
|
|
|
directory](@example/).
|
|
|
|
|
2020-11-03 22:20:29 +00:00
|
|
|
The second approach uses the `#[rocket::main]` route attribute.
|
|
|
|
`#[rocket::main]` _also_ generates a `main` function that sets up an async
|
|
|
|
runtime but unlike `#[launch]`, allows _you_ to start the server:
|
2020-11-03 20:50:31 +00:00
|
|
|
|
2020-11-03 22:20:29 +00:00
|
|
|
```rust,no_run
|
2020-11-03 20:50:31 +00:00
|
|
|
# #[macro_use] extern crate rocket;
|
|
|
|
#
|
|
|
|
# #[get("/world")]
|
|
|
|
# fn world() -> &'static str {
|
|
|
|
# "Hello, world!"
|
|
|
|
# }
|
|
|
|
|
2020-11-03 22:20:29 +00:00
|
|
|
#[rocket::main]
|
2020-11-03 20:50:31 +00:00
|
|
|
async fn main() {
|
|
|
|
rocket::ignite()
|
|
|
|
.mount("/hello", routes![world])
|
|
|
|
.launch()
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2020-11-03 22:20:29 +00:00
|
|
|
`#[rocket::main]` is useful when a handle to the `Future` returned by `launch()`
|
|
|
|
is desired, or when the return value of [`launch()`] is to be inspected. The
|
2021-04-08 02:01:48 +00:00
|
|
|
[error handling example] for instance, inspects the return value.
|
2020-11-03 20:50:31 +00:00
|
|
|
|
|
|
|
[`launch()`]: @api/rocket/struct.Rocket.html#method.launch
|
2021-04-08 02:01:48 +00:00
|
|
|
[error handling example]: @example/error-handling
|
2020-01-16 00:12:44 +00:00
|
|
|
|
|
|
|
## Futures and Async
|
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
Rocket uses Rust [`Future`]s for concurrency. Asynchronous programming with
|
2020-01-16 00:12:44 +00:00
|
|
|
`Future`s and `async/await` allows route handlers to perform wait-heavy I/O such
|
2020-11-03 20:50:31 +00:00
|
|
|
as filesystem and network access while still allowing other requests to be make
|
|
|
|
progress. For an overview of Rust `Future`s, see [Asynchronous Programming in
|
2020-01-16 00:12:44 +00:00
|
|
|
Rust](https://rust-lang.github.io/async-book/).
|
|
|
|
|
|
|
|
In general, you should prefer to use async-ready libraries instead of
|
|
|
|
synchronous equivalents inside Rocket applications.
|
|
|
|
|
|
|
|
`async` appears in several places in Rocket:
|
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
* [Routes] and [Error Catchers] can be `async fn`s. Inside an `async fn`, you
|
|
|
|
can `.await` `Future`s from Rocket or other libraries.
|
|
|
|
* Several of Rocket's traits, such as [`FromData`] and [`FromRequest`], have
|
|
|
|
methods that return `Future`s.
|
|
|
|
* [`Data`] and [`DataStream`], incoming request data, and `Response` and `Body`,
|
|
|
|
outgoing response data, are based on `tokio::io::AsyncRead` instead of
|
2020-01-16 00:12:44 +00:00
|
|
|
`std::io::Read`.
|
|
|
|
|
|
|
|
You can find async-ready libraries on [crates.io](https://crates.io) with the
|
|
|
|
`async` tag.
|
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
[`Future`]: @std/future/trait.Future.html
|
|
|
|
[`Data`]: @api/rocket/struct.Data.html
|
|
|
|
[`DataStream`]: @api/rocket/data/struct.DataStream.html
|
|
|
|
[Routes]: ../requests
|
|
|
|
[Error Catchers]: ../requests#error-catchers
|
|
|
|
[`FromData`]: ../requests#body-data
|
|
|
|
[`FromRequest`]: ../requests#request-guards
|
|
|
|
|
2020-01-16 00:12:44 +00:00
|
|
|
! note
|
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
Rocket master uses the tokio runtime. The runtime is started for you if you
|
2020-11-03 22:20:29 +00:00
|
|
|
use `#[launch]` or `#[rocket::main]`, but you can still `launch()` a Rocket
|
|
|
|
instance on a custom-built runtime by not using _either_ attribute.
|
2020-01-16 00:12:44 +00:00
|
|
|
|
UTF-8 routes. Forms revamp. Temp files. Capped.
So. Many. Changes.
This is an insane commit: simultaneously one of the best (because of all
the wonderful improvements!) and one of the worst (because it is just
massive) in the project's history.
Routing:
* All UTF-8 characters are accepted everywhere in route paths. (#998)
* `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]`
becomes `#[route(GET, uri = "..")]`.
Forms Revamp
* All form related types now reside in a new `form` module.
* Multipart forms are supported. (resolves #106)
* Collections are supported in forms and queries. (resolves #205)
* Nested structures in forms and queries are supported. (resolves #313)
* Form fields can be ad-hoc validated with `#[field(validate = expr)]`.
* `FromFormValue` is now `FromFormField`, blanket implements `FromForm`.
* Form field values are always percent-decoded apriori.
Temporary Files
* A new `TempFile` data and form guard allows streaming data directly to a
file which can then be persisted.
* A new `temp_dir` config parameter specifies where to store `TempFile`.
* The limits `file` and `file/$ext`, where `$ext` is the file extension,
determines the data limit for a `TempFile`.
Capped
* A new `Capped` type is used to indicate when data has been truncated due to
incoming data limits. It allows checking whether data is complete or
truncated.
* `DataStream` methods return `Capped` types.
* `DataStream` API has been revamped to account for `Capped` types.
* Several `Capped<T>` types implement `FromData`, `FromForm`.
* HTTP 413 (Payload Too Large) errors are now returned when data limits are
exceeded. (resolves #972)
Hierarchical Limits
* Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c`
falls back to `a/b` then `a`.
Core
* `&RawStr` no longer implements `FromParam`.
* `&str` implements `FromParam`, `FromData`, `FromForm`.
* `FromTransformedData` was removed.
* `FromData` gained a lifetime for use with request-local data.
* The default error HTML is more compact.
* `&Config` is a request guard.
* The `DataStream` interface was entirely revamped.
* `State` is only exported via `rocket::State`.
* A `request::local_cache!()` macro was added for storing values in
request-local cache without consideration for type uniqueness by using a
locally generated anonymous type.
* `Request::get_param()` is now `Request::param()`.
* `Request::get_segments()` is now `Request::segments()`, takes a range.
* `Request::get_query_value()` is now `Request::query_value()`, can parse any
`FromForm` including sequences.
* `std::io::Error` implements `Responder` like `Debug<std::io::Error>`.
* `(Status, R)` where `R: Responder` implements `Responder` by overriding the
`Status` of `R`.
* The name of a route is printed first during route matching.
* `FlashMessage` now only has one lifetime generic.
HTTP
* `RawStr` implements `serde::{Serialize, Deserialize}`.
* `RawStr` implements _many_ more methods, in particular, those related to the
`Pattern` API.
* `RawStr::from_str()` is now `RawStr::new()`.
* `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as
necessary, return `Cow`.
* `Status` implements `Default` with `Status::Ok`.
* `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`.
* Authority and origin part of `Absolute` can be modified with new
`Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods.
* `Origin::segments()` was removed in favor of methods split into query and
path parts and into raw and decoded versions.
* The `Segments` iterator is smarter, returns decoded `&str` items.
* `Segments::into_path_buf()` is now `Segments::to_path_buf()`.
* A new `QuerySegments` is the analogous query segment iterator.
* Once set, `expires` on private cookies is not overwritten. (resolves #1506)
* `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`.
Codegen
* Preserve more spans in `uri!` macro.
* Preserve spans `FromForm` field types.
* All dynamic parameters in a query string must typecheck as `FromForm`.
* `FromFormValue` derive removed; `FromFormField` added.
* The `form` `FromForm` and `FromFormField` field attribute is now named
`field`. `#[form(field = ..)]` is now `#[field(name = ..)]`.
Contrib
* `Json` implements `FromForm`.
* `MsgPack` implements `FromForm`.
* The `json!` macro is exported as `rocket_contrib::json::json!`.
* Added clarifying docs to `StaticFiles`.
Examples
* `form_validation` and `form_kitchen_sink` removed in favor of `forms`.
* The `hello_world` example uses unicode in paths.
* The `json` example only allocates as necessary.
Internal
* Codegen uses new `exports` module with the following conventions:
- Locals starts with `__` and are lowercased.
- Rocket modules start with `_` and are lowercased.
- `std` types start with `_` and are titlecased.
- Rocket types are titlecased.
* A `header` module was added to `http`, contains header types.
* `SAFETY` is used as doc-string keyword for `unsafe` related comments.
* The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
|
|
|
### Async Routes
|
|
|
|
|
|
|
|
Rocket makes it easy to use `async/await` in routes.
|
|
|
|
|
|
|
|
```rust
|
|
|
|
# #[macro_use] extern crate rocket;
|
|
|
|
use rocket::tokio::time::{sleep, Duration};
|
2021-03-27 23:25:39 +00:00
|
|
|
|
UTF-8 routes. Forms revamp. Temp files. Capped.
So. Many. Changes.
This is an insane commit: simultaneously one of the best (because of all
the wonderful improvements!) and one of the worst (because it is just
massive) in the project's history.
Routing:
* All UTF-8 characters are accepted everywhere in route paths. (#998)
* `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]`
becomes `#[route(GET, uri = "..")]`.
Forms Revamp
* All form related types now reside in a new `form` module.
* Multipart forms are supported. (resolves #106)
* Collections are supported in forms and queries. (resolves #205)
* Nested structures in forms and queries are supported. (resolves #313)
* Form fields can be ad-hoc validated with `#[field(validate = expr)]`.
* `FromFormValue` is now `FromFormField`, blanket implements `FromForm`.
* Form field values are always percent-decoded apriori.
Temporary Files
* A new `TempFile` data and form guard allows streaming data directly to a
file which can then be persisted.
* A new `temp_dir` config parameter specifies where to store `TempFile`.
* The limits `file` and `file/$ext`, where `$ext` is the file extension,
determines the data limit for a `TempFile`.
Capped
* A new `Capped` type is used to indicate when data has been truncated due to
incoming data limits. It allows checking whether data is complete or
truncated.
* `DataStream` methods return `Capped` types.
* `DataStream` API has been revamped to account for `Capped` types.
* Several `Capped<T>` types implement `FromData`, `FromForm`.
* HTTP 413 (Payload Too Large) errors are now returned when data limits are
exceeded. (resolves #972)
Hierarchical Limits
* Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c`
falls back to `a/b` then `a`.
Core
* `&RawStr` no longer implements `FromParam`.
* `&str` implements `FromParam`, `FromData`, `FromForm`.
* `FromTransformedData` was removed.
* `FromData` gained a lifetime for use with request-local data.
* The default error HTML is more compact.
* `&Config` is a request guard.
* The `DataStream` interface was entirely revamped.
* `State` is only exported via `rocket::State`.
* A `request::local_cache!()` macro was added for storing values in
request-local cache without consideration for type uniqueness by using a
locally generated anonymous type.
* `Request::get_param()` is now `Request::param()`.
* `Request::get_segments()` is now `Request::segments()`, takes a range.
* `Request::get_query_value()` is now `Request::query_value()`, can parse any
`FromForm` including sequences.
* `std::io::Error` implements `Responder` like `Debug<std::io::Error>`.
* `(Status, R)` where `R: Responder` implements `Responder` by overriding the
`Status` of `R`.
* The name of a route is printed first during route matching.
* `FlashMessage` now only has one lifetime generic.
HTTP
* `RawStr` implements `serde::{Serialize, Deserialize}`.
* `RawStr` implements _many_ more methods, in particular, those related to the
`Pattern` API.
* `RawStr::from_str()` is now `RawStr::new()`.
* `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as
necessary, return `Cow`.
* `Status` implements `Default` with `Status::Ok`.
* `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`.
* Authority and origin part of `Absolute` can be modified with new
`Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods.
* `Origin::segments()` was removed in favor of methods split into query and
path parts and into raw and decoded versions.
* The `Segments` iterator is smarter, returns decoded `&str` items.
* `Segments::into_path_buf()` is now `Segments::to_path_buf()`.
* A new `QuerySegments` is the analogous query segment iterator.
* Once set, `expires` on private cookies is not overwritten. (resolves #1506)
* `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`.
Codegen
* Preserve more spans in `uri!` macro.
* Preserve spans `FromForm` field types.
* All dynamic parameters in a query string must typecheck as `FromForm`.
* `FromFormValue` derive removed; `FromFormField` added.
* The `form` `FromForm` and `FromFormField` field attribute is now named
`field`. `#[form(field = ..)]` is now `#[field(name = ..)]`.
Contrib
* `Json` implements `FromForm`.
* `MsgPack` implements `FromForm`.
* The `json!` macro is exported as `rocket_contrib::json::json!`.
* Added clarifying docs to `StaticFiles`.
Examples
* `form_validation` and `form_kitchen_sink` removed in favor of `forms`.
* The `hello_world` example uses unicode in paths.
* The `json` example only allocates as necessary.
Internal
* Codegen uses new `exports` module with the following conventions:
- Locals starts with `__` and are lowercased.
- Rocket modules start with `_` and are lowercased.
- `std` types start with `_` and are titlecased.
- Rocket types are titlecased.
* A `header` module was added to `http`, contains header types.
* `SAFETY` is used as doc-string keyword for `unsafe` related comments.
* The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
|
|
|
#[get("/delay/<seconds>")]
|
|
|
|
async fn delay(seconds: u64) -> String {
|
|
|
|
sleep(Duration::from_secs(seconds)).await;
|
|
|
|
format!("Waited for {} seconds", seconds)
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
First, notice that the route function is an `async fn`. This enables the use of
|
|
|
|
`await` inside the handler. `sleep` is an asynchronous function, so we must
|
|
|
|
`await` it.
|
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
### Multitasking
|
2020-01-16 00:12:44 +00:00
|
|
|
|
|
|
|
Rust's `Future`s are a form of *cooperative multitasking*. In general, `Future`s
|
2020-11-03 20:50:31 +00:00
|
|
|
and `async fn`s should only `.await` on operations and never block. Some common
|
|
|
|
examples of blocking include locking non-`async` mutexes, joining threads, or
|
|
|
|
using non-`async` library functions (including those in `std`) that perform I/O.
|
2020-01-16 00:12:44 +00:00
|
|
|
|
|
|
|
If a `Future` or `async fn` blocks the thread, inefficient resource usage,
|
|
|
|
stalls, or sometimes even deadlocks can occur.
|
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
Sometimes there is no good `async` alternative for a library or operation. If
|
|
|
|
necessary, you can convert a synchronous operation to an async one with
|
|
|
|
[`tokio::task::spawn_blocking`]:
|
|
|
|
|
|
|
|
```rust
|
|
|
|
# #[macro_use] extern crate rocket;
|
|
|
|
use std::io;
|
|
|
|
use rocket::tokio::task::spawn_blocking;
|
|
|
|
use rocket::response::Debug;
|
|
|
|
|
|
|
|
#[get("/blocking_task")]
|
|
|
|
async fn blocking_task() -> Result<Vec<u8>, Debug<io::Error>> {
|
|
|
|
// In a real app, use rocket::response::NamedFile or tokio::fs::File.
|
|
|
|
let vec = spawn_blocking(|| std::fs::read("data.txt")).await
|
|
|
|
.map_err(|e| io::Error::new(io::ErrorKind::Interrupted, e))??;
|
|
|
|
|
|
|
|
Ok(vec)
|
|
|
|
}
|
|
|
|
```
|
2020-01-16 00:12:44 +00:00
|
|
|
|
2020-11-03 20:50:31 +00:00
|
|
|
[`tokio::task::spawn_blocking`]: @tokio/task/fn.spawn_blocking.html
|