From d0047d2c92f0c8a0887718458ca8e9865ed9c532 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Wed, 19 Jun 2024 23:45:12 +0200 Subject: [PATCH] add rocket --- technology/dev/Development.md | 3 +- .../dev/programming/frameworks/Rocket.md | 1537 +++++++++++++++++ 2 files changed, 1539 insertions(+), 1 deletion(-) create mode 100644 technology/dev/programming/frameworks/Rocket.md diff --git a/technology/dev/Development.md b/technology/dev/Development.md index c65b130..caf70f4 100644 --- a/technology/dev/Development.md +++ b/technology/dev/Development.md @@ -1,7 +1,7 @@ --- tags: ["meta"] obj: meta/collection -rev: 2024-05-02 +rev: 2024-06-19 --- # Development @@ -16,6 +16,7 @@ rev: 2024-05-02 - [TailwindCSS](TailwindCSS.md) - [Flutter](./programming/frameworks/Flutter.md) - [Godot Game Engine](./programming/Godot.md) +- [Rocket](./programming/frameworks/Rocket.md) ## Tools - [Git](Git.md) \ No newline at end of file diff --git a/technology/dev/programming/frameworks/Rocket.md b/technology/dev/programming/frameworks/Rocket.md new file mode 100644 index 0000000..6527570 --- /dev/null +++ b/technology/dev/programming/frameworks/Rocket.md @@ -0,0 +1,1537 @@ +--- +obj: concept +website: https://rocket.rs +rev: 2024-06-19 +--- + +# Rocket.rs +Rocket provides primitives to build web servers and applications with [Rust](../languages/Rust.md). + +## 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 process that goes from request to response the "lifecycle". We summarize the lifecycle as the following sequence of steps: + +1. **Routing** + Rocket parses an incoming [HTTP](../../../internet/HTTP.md) 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. +2. **Validation** + 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_. +3. **Processing** + 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`. +4. **Response** + The returned `Response` is processed. Rocket generates the appropriate [HTTP](../../../internet/HTTP.md) response and sends it to the client. This completes the lifecycle. Rocket continues listening for requests, restarting the lifecycle for each incoming request. + + +## Routing +Rocket applications are centered around routes and handlers. A _route_ is a combination of: + +- A set of parameters to match an incoming request against. +- A handler to process the request and return a response. + +A _handler_ is simply a function that takes an arbitrary number of arguments and returns any arbitrary type. + +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 +#[get("/world")] // <- route attribute +fn world() -> &'static str { // <- request handler + "hello, world!" +} +``` + +## Mounting +Before Rocket can dispatch requests to a route, the route needs to be _mounted_: +```rust +rocket::build().mount("/hello", routes![world]); +``` + +The `mount` method takes as input: +1. A _base_ path to namespace a list of routes under, here, `/hello`. +2. A list of routes via the `routes!` macro: here, `routes![world]`, with multiple routes: `routes![a, b, c]`. + +This creates a new `Rocket` instance via the `build` function and mounts the `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 +rocket::build() + .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. + + > **Note**: In many cases, the base path will simply be `"/"`. +  +## Launching +Rocket begins serving requests after being _launched_, which starts a multi-threaded asynchronous server and dispatches requests to matching routes as they arrive. + +There are two mechanisms 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: +```rust +#[macro_use] extern crate rocket; + +#[get("/world")] +fn world() -> &'static str { + "Hello, world!" +} + +#[launch] +fn rocket() -> _ { + rocket::build().mount("/hello", routes![world]) +} +``` + +## Requests +Together, a `route` attribute and function signature specify what must be true about a request in order for the route's handler to be called. You've already seen an example of this in action: +```rust +#[get("/world")] +fn handler() { /* .. */ } +``` + +This route indicates that it only matches against `GET` requests to the `/world` route. Rocket ensures that this is the case before `handler` is called. Of course, you can do much more than specify the method and path of a request. Among other things, you can ask Rocket to automatically validate: +- The type of a dynamic path segment. +- The type of _several_ dynamic path segments. +- The type of incoming body data. +- The types of query strings, forms, and form values. +- The expected incoming or outgoing format of a request. +- Any arbitrary, user-defined security or validation policies. + +The route attribute and function signature work in tandem to describe these validations. Rocket's code generation takes care of actually validating the properties. This section describes how to ask Rocket to validate against all of these properties and more. + +### Methods +A Rocket route attribute can be any one of `get`, `put`, `post`, `delete`, `head`, `patch`, or `options`, each corresponding to the [HTTP](../../../internet/HTTP.md) method to match against. For example, the following attribute will match against `POST` requests to the root path: +```rust +#[post("/")] +``` + +The grammar for these attributes is defined formally in the [`route`](https://api.rocket.rs/v0.5/rocket/attr.route.html) API docs. + +#### HEAD Requests +Rocket handles `HEAD` requests automatically when there exists a `GET` route that would otherwise match. It does this by stripping the body from the response, if there is one. You can also specialize the handling of a `HEAD` request by declaring a route for it; Rocket won't interfere with `HEAD` requests your application explicitly handles. + + +### Dynamic Paths +You can declare path segments as dynamic by using angle brackets around variable names in a route's path. For example, if we want to say _Hello!_ to anything, not just the world, we can declare a route like so: +```rust +#[get("/hello/")] +fn hello(name: &str) -> String { + format!("Hello, {}!", name) +} +``` + +If we were to mount the path at the root (`.mount("/", routes![hello])`), then any request to a path with two non-empty segments, where the first segment is `hello`, will be dispatched to the `hello` route. For example, if we were to visit `/hello/John`, the application would respond with `Hello, John!`. + +Any number of dynamic path segments are allowed. A path segment can be of any type, including your own, as long as the type implements the [`FromParam`](https://api.rocket.rs/v0.5/rocket/request/trait.FromParam.html) trait. We call these types _parameter guards_. Rocket implements `FromParam` for many of the standard library types, as well as a few special Rocket types. For the full list of provided implementations, see the [`FromParam` API docs](https://api.rocket.rs/v0.5/rocket/request/trait.FromParam.html). Here's a more complete route to illustrate varied usage: +```rust +#[get("/hello///")] +fn hello(name: &str, age: u8, cool: bool) -> String { + if cool { + format!("You're a cool {} year old, {}!", age, name) + } else { + format!("{}, we need to talk about your coolness.", name) + } +} +``` + +#### Multiple Segments +You can also match against multiple segments by using `` in a route path. The type of such parameters, known as _segments guards_, must implement [`FromSegments`](https://api.rocket.rs/v0.5/rocket/request/trait.FromSegments.html). A segments guard must be the final component of a path: any text after a segments guard will result in a compile-time error. + +As an example, the following route matches against all paths that begin with `/page`: +```rust +use std::path::PathBuf; + +#[get("/page/")] +fn get_page(path: PathBuf) { /* ... */ } +``` + +The path after `/page/` will be available in the `path` parameter, which may be empty for paths that are simply `/page`, `/page/`, `/page//`, and so on. The `FromSegments` implementation for `PathBuf` ensures that `path` cannot lead to [path traversal attacks](https://owasp.org/www-community/attacks/Path_Traversal). With this, a safe and secure static file server can be implemented in just 4 lines: +```rust +use std::path::{Path, PathBuf}; +use rocket::fs::NamedFile; + +#[get("/")] +async fn files(file: PathBuf) -> Option { + NamedFile::open(Path::new("static/").join(file)).await.ok() +} +``` + +Rocket makes it even _easier_ to serve static files! + +If you need to serve static files from your Rocket application, consider using [`FileServer`](https://api.rocket.rs/v0.5/rocket/fs/struct.FileServer.html), which makes it as simple as: +```rust +use rocket::fs::FileServer; + +#[launch] +fn rocket() -> _ { + rocket::build() + // serve files from `/www/static` at path `/public` + .mount("/public", FileServer::from("/www/static")) +} +``` + + +#### Ignored Segments +A component of a route can be fully ignored by using `<_>`, and multiple components can be ignored by using `<_..>`. In other words, the wildcard name `_` is a dynamic parameter name that ignores that dynamic parameter. An ignored parameter must not appear in the function argument list. A segment declared as `<_>` matches anything in a single segment while segments declared as `<_..>` match any number of segments with no conditions. + +As an example, the `foo_bar` route below matches any `GET` request with a 3-segment URI that starts with `/foo/` and ends with `/bar`. The `everything` route below matches _every_ GET request. +```rust +#[get("/foo/<_>/bar")] +fn foo_bar() -> &'static str { + "Foo _____ bar!" +} + +#[get("/<_..>")] +fn everything() -> &'static str { + "Hey, you're here." +} +``` + +### Request Guards +Request guards are one of Rocket's most powerful instruments. As the name might imply, a request guard protects a handler from being called erroneously based on information contained in an incoming request. More specifically, a request guard is a type that represents an arbitrary validation policy. The validation policy is implemented through the [`FromRequest`](https://api.rocket.rs/v0.5/rocket/request/trait.FromRequest.html) trait. Every type that implements `FromRequest` is a request guard. + +Request guards appear as inputs to handlers. An arbitrary number of request guards can appear as arguments in a route handler. Rocket will automatically invoke the [`FromRequest`](https://api.rocket.rs/v0.5/rocket/request/trait.FromRequest.html) implementation for request guards before calling the handler. Rocket only dispatches requests to a handler when all of its guards pass. + +For instance, the following dummy handler makes use of three request guards, `A`, `B`, and `C`. An input can be identified as a request guard if it is not named in the route attribute. +```rust +#[get("/")] +fn index(param: isize, a: A, b: B, c: C) { /* ... */ } +``` + +Request guards always fire in left-to-right declaration order. In the example above, the order will be `A` followed by `B` followed by `C`. Errors are short-circuiting; if one guard fails, the remaining are not attempted. To learn more about request guards and implementing them, see the [`FromRequest`](https://api.rocket.rs/v0.5/rocket/request/trait.FromRequest.html) documentation. + +#### Custom Guards +You can implement `FromRequest` for your own types. For instance, to protect a `sensitive` route from running unless an `ApiKey` is present in the request headers, you might create an `ApiKey` type that implements `FromRequest` and then use it as a request guard: +```rust +#[get("/sensitive")] +fn sensitive(key: ApiKey) { /* .. */ } +``` + +You might also implement `FromRequest` for an `AdminUser` type that authenticates an administrator using incoming cookies. Then, any handler with an `AdminUser` or `ApiKey` type in its argument list is assured to only be invoked if the appropriate conditions are met. Request guards centralize policies, resulting in a simpler, safer, and more secure applications. + +### Cookies +A reference to a [`CookieJar`](https://api.rocket.rs/v0.5/rocket/http/struct.CookieJar.html) is an important, built-in request guard: it allows you to get, set, and remove cookies. Because `&CookieJar` is a request guard, an argument of its type can simply be added to a handler: +```rust +use rocket::http::CookieJar; + +#[get("/")] +fn index(cookies: &CookieJar<'_>) -> Option { + cookies.get("message").map(|crumb| format!("Message: {}", crumb.value())) +} +``` + +This results in the incoming request's cookies being accessible from the handler. The example above retrieves a [cookie](../../../internet/Cookie.md) named `message`. Cookies can also be set and removed using the `CookieJar` guard. The [cookies example](https://github.com/rwf2/Rocket/tree/v0.5/examples/cookies) on [GitHub](../../../applications/development/GitHub.md) illustrates further use of the `CookieJar` type to get and set cookies, while the [`CookieJar`](https://api.rocket.rs/v0.5/rocket/http/struct.CookieJar.html) documentation contains complete usage information. + +#### Private Cookies +Cookies added via the [`CookieJar::add()`](https://api.rocket.rs/v0.5/rocket/http/struct.CookieJar.html#method.add) method are set _in the clear._ In other words, the value set is visible to the client. For sensitive data, Rocket provides _private_ cookies. Private cookies are similar to regular cookies except that they are encrypted using authenticated encryption, a form of encryption which simultaneously provides confidentiality, integrity, and authenticity. Thus, private cookies cannot be inspected, tampered with, or manufactured by clients. If you prefer, you can think of private cookies as being signed and encrypted. + +Support for private cookies must be manually enabled via the `secrets` crate feature: +```toml +## in Cargo.toml +rocket = { version = "0.5.1", features = ["secrets"] } +``` + +The API for retrieving, adding, and removing private cookies is identical except that most methods are suffixed with `_private`. These methods are: [`get_private`](https://api.rocket.rs/v0.5/rocket/http/struct.CookieJar.html#method.get_private), [`add_private`](https://api.rocket.rs/v0.5/rocket/http/struct.CookieJar.html#method.add_private), and [`remove_private`](https://api.rocket.rs/v0.5/rocket/http/struct.CookieJar.html#method.remove_private). An example of their usage is below: +```rust +use rocket::http::{Cookie, CookieJar}; +use rocket::response::{Flash, Redirect}; + +/// Retrieve the user's ID, if any. +#[get("/user_id")] +fn user_id(cookies: &CookieJar<'_>) -> Option { + cookies.get_private("user_id") + .map(|crumb| format!("User ID: {}", crumb.value())) +} + +/// Remove the `user_id` cookie. +#[post("/logout")] +fn logout(cookies: &CookieJar<'_>) -> Flash { + cookies.remove_private("user_id"); + Flash::success(Redirect::to("/"), "Successfully logged out.") +} +``` + +#### Secret Key +To encrypt private cookies, Rocket uses the 256-bit key specified in the `secret_key` configuration parameter. When compiled in debug mode, a fresh key is generated automatically. In release mode, Rocket requires you to set a secret key if the `secrets` feature is enabled. Failure to do so results in a hard error at launch time. The value of the parameter may either be a 256-bit [base64](../../../files/Base64.md) or hex string or a 32-byte slice. + +Generating a string suitable for use as a `secret_key` configuration value is usually done through tools like [`openssl`](../../../cryptography/OpenSSL.md). Using [`openssl`](../../../cryptography/OpenSSL.md), a 256-bit [base64](../../../files/Base64.md) key can be generated with the command `openssl rand -base64 32`. + +For more information on configuration, see [Configuration](https://rocket.rs/guide/v0.5/configuration/). + +### Body Data +Body data processing, like much of Rocket, is type directed. To indicate that a handler expects body data, annotate it with `data = ""`, where `param` is an argument in the handler. The argument's type must implement the [`FromData`](https://api.rocket.rs/v0.5/rocket/data/trait.FromData.html) trait. It looks like this, where `T` is assumed to implement `FromData`: +```rust +#[post("/", data = "")] +fn new(input: T) { /* .. */ } +``` + +Any type that implements [`FromData`](https://api.rocket.rs/v0.5/rocket/data/trait.FromData.html) is also known as _a data guard_. + +#### JSON +The [`Json`](https://api.rocket.rs/v0.5/rocket/serde/json/struct.Json.html) guard deserializes body data as [JSON](../../../files/JSON.md). The only condition is that the generic type `T` implements the `Deserialize` trait from [`serde`](https://serde.rs/). + +```rust +use rocket::serde::{Deserialize, json::Json}; + +#[derive(Deserialize)] +#[serde(crate = "rocket::serde")] +struct Task<'r> { + description: &'r str, + complete: bool +} + +#[post("/todo", data = "")] +fn new(task: Json>) { /* .. */ } +``` + +> [JSON](../../../files/JSON.md) support requires enabling Rocket's `json` feature flag. + +Rocket intentionally places [JSON](../../../files/JSON.md) support, as well support for other data formats and features, behind feature flags. See [the api docs](https://api.rocket.rs/v0.5/rocket/#features) for a list of available features. The `json` feature can be enabled in the `Cargo.toml`: + +```toml +rocket = { version = "0.5.1", features = ["json"] } +``` + +#### Temporary Files +The [`TempFile`](https://api.rocket.rs/v0.5/rocket/fs/enum.TempFile.html) data guard streams data directly to a temporary file which can then be persisted. It makes accepting file uploads trivial: + +```rust +use rocket::fs::TempFile; + +#[post("/upload", format = "plain", data = "")] +async fn upload(mut file: TempFile<'_>) -> std::io::Result<()> { + file.persist_to(permanent_location).await +} +``` + +#### Streaming +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 possible via the [`Data`](https://api.rocket.rs/v0.5/rocket/data/struct.Data.html) type: + +```rust +use rocket::tokio; + +use rocket::data::{Data, ToByteUnit}; + +#[post("/debug", 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(()) +} +``` + +The route above accepts any `POST` request to the `/debug` path. At most 512KiB of the incoming is streamed out to `stdout`. If the upload fails, an error response is returned. + +### Forms +Forms are one of the most common types of data handled in web applications, and Rocket makes handling them easy. Rocket supports both `multipart` and `x-www-form-urlencoded` forms out of the box, enabled by the [`Form`](https://api.rocket.rs/v0.5/rocket/form/struct.Form.html) data guard and derivable [`FromForm`](https://api.rocket.rs/v0.5/rocket/form/trait.FromForm.html) trait. + +Say your application is processing a form submission for a new todo `Task`. The form contains two fields: `complete`, a checkbox, and `type`, a text field. You can easily handle the form request in Rocket as follows: + +```rust +use rocket::form::Form; + +#[derive(FromForm)] +struct Task<'r> { + complete: bool, + r#type: &'r str, +} + +#[post("/todo", data = "")] +fn new(task: Form>) { /* .. */ } +``` + +#### Multipart +Multipart forms are handled transparently, with no additional effort. Most `FromForm` types can parse themselves from the incoming data stream. For example, here's a form and route that accepts a multipart file upload using [`TempFile`](https://api.rocket.rs/v0.5/rocket/fs/enum.TempFile.html): + +```rust +use rocket::form::Form; +use rocket::fs::TempFile; + +#[derive(FromForm)] +struct Upload<'r> { + save: bool, + file: TempFile<'r>, +} + +#[post("/upload", data = "")] +fn upload_form(upload: Form>) { /* .. */ } +``` + +#### Parsing Strategy +Rocket's `FromForm` parsing is _lenient_ by default: a `Form` will parse successfully from an incoming form even if it contains extra, duplicate, or missing fields. Extras or duplicates are ignored -- no validation or parsing of the fields occurs -- and missing fields are filled with defaults when available. To change this behavior and make form parsing _strict_, use the [`Form>`](https://api.rocket.rs/v0.5/rocket/form/struct.Strict.html) data type, which emits errors if there are any extra or missing fields, irrespective of defaults. + +You can use a `Form>` anywhere you'd use a `Form`. Its generic parameter is also required to implement `FromForm`. For instance, we can simply replace `Form` with `Form>` above to get strict parsing: + +```rust +use rocket::form::{Form, Strict}; + +#[post("/todo", data = "")] +fn new(task: Form>>) { /* .. */ } +``` + +`Strict` can also be used to make individual fields strict while keeping the overall structure and remaining fields lenient: + +```rust +#[derive(FromForm)] +struct Input { + required: Strict, + uses_default: bool +} + +#[post("/", data = "")] +fn new(input: Form) { /* .. */ } +``` + +[`Lenient`](https://api.rocket.rs/v0.5/rocket/form/struct.Lenient.html) is the _lenient_ analog to `Strict`, which forces parsing to be lenient. `Form` is lenient by default, so a `Form>` is redundant, but `Lenient` can be used to overwrite a strict parse as lenient: `Option>`. + +#### Defaults +A form guard may specify a default value to use when a field is missing. The default value is used only when parsing is _lenient_. When _strict_, all errors, including missing fields, are propagated directly. + +Some types with defaults include `bool`, which defaults to `false`, useful for checkboxes, `Option`, which defaults to `None`, and [`form::Result`](https://api.rocket.rs/v0.5/rocket/form/type.Result.html), which defaults to `Err(Missing)` or otherwise collects errors in an `Err` of [`Errors<'_>`](https://api.rocket.rs/v0.5/rocket/form/struct.Errors.html). Defaulting guards can be used just like any other form guard: + +```rust +use rocket::form::{self, Errors}; + +#[derive(FromForm)] +struct MyForm<'v> { + maybe_string: Option<&'v str>, + ok_or_error: form::Result<'v, Vec<&'v str>>, + here_or_false: bool, +} +``` + +The default can be overridden or unset using the `#[field(default = expr)]` field attribute. If `expr` is not literally `None`, the parameter sets the default value of the field to be `expr.into()`. If `expr` _is_ `None`, the parameter _unsets_ the default value of the field, if any. + +```rust +#[derive(FromForm)] +struct MyForm { + // Set the default value to be `"hello"`. + // + // Note how an `&str` is automatically converted into a `String`. + #[field(default = "hello")] + greeting: String, + // Remove the default value of `false`, requiring all parses of `MyForm` + // to contain an `is_friendly` field. + #[field(default = None)] + is_friendly: bool, +} +``` + +See the [`FromForm` derive](https://api.rocket.rs/v0.5/rocket/derive.FromForm.html) documentation for full details on the `default` attribute parameter as well documentation on the more expressive `default_with` parameter option. + +#### Field Renaming +By default, Rocket matches the name of an incoming form field to the name of a structure field. While this behavior is typical, it may also be desired to use different names for form fields and struct fields while still parsing as expected. You can ask Rocket to look for a different form field for a given structure field by using one or more `#[field(name = "name")]` or `#[field(name = uncased("name")]` field annotation. The `uncased` variant case-insensitively matches field names. + +As an example, say that you're writing an application that receives data from an external service. The external service `POST`s a form with a field named `first-Name` which you'd like to write as `first_name` in Rust. Such a form structure can be written as: + +```rust +#[derive(FromForm)] +struct External<'r> { + #[field(name = "first-Name")] + first_name: &'r str +} +``` + +If you want to accept both `firstName` case-insensitively as well as `first_name` case-sensitively, you'll need to use two annotations: + +```rust +#[derive(FromForm)] +struct External<'r> { + #[field(name = uncased("firstName"))] + #[field(name = "first_name")] + first_name: &'r str +} +``` + +This will match any casing of `firstName` including `FirstName`, `firstname`, `FIRSTname`, and so on, but only match exactly on `first_name`. + +If instead you wanted to match any of `first-name`, `first_name` or `firstName`, in each instance case-insensitively, you would write: + +```rust +#[derive(FromForm)] +struct External<'r> { + #[field(name = uncased("first-name"))] + #[field(name = uncased("first_name"))] + #[field(name = uncased("firstname"))] + first_name: &'r str +} +``` + +Cased and uncased renamings can be mixed and matched, and any number of renamings is allowed. Rocket will emit an error at compile-time if field names conflict, preventing ambiguous parsing at runtime. + +#### Ad-Hoc Validation +Fields of forms can be easily ad-hoc validated via the `#[field(validate)]` attribute. As an example, consider a form field `age: u16` which we'd like to ensure is greater than `21`. The following structure accomplishes this: + +```rust +#[derive(FromForm)] +struct Person { + #[field(validate = range(21..))] + age: u16 +} +``` + +The expression `range(21..)` is a call to [`form::validate::range`](https://api.rocket.rs/v0.5/rocket/form/validate/fn.range.html). Rocket passes a borrow of the attributed field, here `self.age`, as the first parameter to the function call. The rest of the fields are pass as written in the expression. + +Any function in the [`form::validate`](https://api.rocket.rs/v0.5/rocket/form/validate/index.html) module can be called, and other fields of the form can be passed in by using `self.$field` where `$field` is the name of the field in the structure. You can also apply more than one validation to a field by using multiple attributes. For example, the following form validates that the value of the field `confirm` is equal to the value of the field `value` and that it doesn't contain `no`: + +```rust +#[derive(FromForm)] +struct Password<'r> { + #[field(name = "password")] + value: &'r str, + #[field(validate = eq(self.value))] + #[field(validate = omits("no"))] + confirm: &'r str, +} +``` + +In reality, the expression after `validate =` can be _any_ expression as long as it evaluates to a value of type `Result<(), Errors<'_>>` (aliased by [`form::Result`](https://api.rocket.rs/v0.5/rocket/form/type.Result.html)), where an `Ok` value means that validation was successful while an `Err` of [`Errors<'_>`](https://api.rocket.rs/v0.5/rocket/form/struct.Errors.html) indicates the error(s) that occurred. For instance, if you wanted to implement an ad-hoc Luhn validator for credit-card-like numbers, you might write: + +```rust +use rocket::time::Date; +use rocket::form::{self, Error}; + +#[derive(FromForm)] +struct CreditCard { + #[field(validate = luhn(self.cvv, &self.expiration))] + number: u64, + #[field(validate = range(..9999))] + cvv: u16, + expiration: Date, +} + +fn luhn<'v>(number: &u64, cvv: u16, exp: &Date) -> form::Result<'v, ()> { + if !valid { + Err(Error::validation("invalid credit card number"))?; + } + + Ok(()) +} +``` + +If a field's validation doesn't depend on other fields (validation is _local_), it is validated prior to those fields that do. For `CreditCard`, `cvv` and `expiration` will be validated prior to `number`. + +#### Wrapping Validators +If a particular validation is applied in more than once place, prefer creating a type that encapsulates and represents the validated value. For example, if your application often validates `age` fields, consider creating a custom `Age` form guard that always applies the validation: + +```rust +#[derive(FromForm)] +#[field(validate = range(18..150))] +struct Age(u16); +``` + +This approach is also useful when a custom validator already exists in some other form. For instance, the following example leverages [`try_with`](https://api.rocket.rs/v0.5/rocket/form/validate/fn.try_with.html) and an existing `FromStr` implementation on a `Token` type to validate a string: + +```rust +use std::str::FromStr; + +#[derive(FromForm)] +#[field(validate = try_with(|s| Token::from_str(s)))] +struct Token<'r>(&'r str); +``` + +### Query Strings +Query strings are URL-encoded forms that appear in the URL of a request. Query parameters are declared like path parameters but otherwise handled like regular URL-encoded form fields. + +#### Static Parameters +A request matches a route _iff_ its query string contains all of the static parameters in the route's query string. A route with a static parameter `param` (any [UTF-8](../../../files/Unicode.md) text string) in a query will only match requests with that exact path segment in its query string. + + This is truly an _iff_! + +Only the static parameters in query route string affect routing. Dynamic parameters are allowed to be missing by default. + +For example, the route below will match requests with path `/` and _at least_ the query segments `hello` and `cat=♥`: + +```rust +#[get("/?hello&cat=♥")] +fn cats() -> &'static str { + "Hello, kittens!" +} + +// The following GET requests match `cats`. `%E2%99%A5` is encoded `♥`. +"/?cat=%E2%99%A5&hello" +"/?hello&cat=%E2%99%A5" +"/?dogs=amazing&hello&there&cat=%E2%99%A5" +``` + +#### Dynamic Parameters +A single dynamic parameter of `` acts identically to a form field declared as `param`. In particular, Rocket will expect the query form to contain a field with key `param` and push the shifted field to the `param` type. As with forms, default values are used when parsing fails. The example below illustrates this with a single value `name`, a collection `color`, a nested form `person`, and an `other` value that will default to `None`: + +```rust +#[derive(Debug, PartialEq, FromFormField)] +enum Color { + Red, + Blue, + Green +} + +#[derive(Debug, PartialEq, FromForm)] +struct Pet<'r> { + name: &'r str, + age: usize, +} + +#[derive(Debug, PartialEq, FromForm)] +struct Person<'r> { + pet: Pet<'r>, +} + +#[get("/?&&&")] +fn hello(name: &str, color: Vec, person: Person<'_>, other: Option) { + assert_eq!(name, "George"); + assert_eq!(color, [Color::Red, Color::Green, Color::Green, Color::Blue]); + assert_eq!(other, None); + assert_eq!(person, Person { + pet: Pet { name: "Fi Fo Alex", age: 1 } + }); +} + +// A request with these query segments matches as above. +name=George&\ +color=red&\ +color=green&\ +person.pet.name=Fi+Fo+Alex&\ +color=green&\ +person.pet.age=1&\ +color=blue&\ +extra=yes\ +``` + +Note that, like forms, parsing is field-ordering insensitive and lenient by default. + +#### Trailing Parameter +A trailing dynamic parameter of `` collects all of the query segments that don't otherwise match a declared static or dynamic parameter. In other words, the otherwise unmatched segments are pushed, unshifted, to the `` type: + +```rust +use rocket::form::Form; + +#[derive(FromForm)] +struct User<'r> { + name: &'r str, + active: bool, +} + +#[get("/?hello&&")] +fn user(id: usize, user: User<'_>) { + assert_eq!(id, 1337); + assert_eq!(user.name, "Bob Smith"); + assert_eq!(user.active, true); +} + +// A request with these query segments matches as above. +hello&\ +name=Bob+Smith&\ +id=1337&\ +active=yes\ +``` + +### Error Catchers +Application processing is fallible. Errors arise from the following sources: + +- A failing guard. +- A failing responder. +- A routing failure. + +If any of these occur, Rocket returns an error to the client. To generate the error, Rocket invokes the _catcher_ corresponding to the error's status code and scope. Catchers are similar to routes except in that: + +1. Catchers are only invoked on error conditions. +2. Catchers are declared with the `catch` attribute. +3. Catchers are _registered_ with [`register()`](https://api.rocket.rs/v0.5/rocket/struct.Rocket.html#method.register) instead of [`mount()`](https://api.rocket.rs/v0.5/rocket/struct.Rocket.html#method.mount). +4. Any modifications to cookies are cleared before a catcher is invoked. +5. Error catchers cannot invoke guards. +6. Error catchers should not fail to produce a response. +7. Catchers are scoped to a path prefix. + +To declare a catcher for a given status code, use the [`catch`](https://api.rocket.rs/v0.5/rocket/attr.catch.html) attribute, which takes a single integer corresponding to the [HTTP](../../../internet/HTTP.md) status code to catch. For instance, to declare a catcher for `404 Not Found` errors, you'd write: + +```rust +use rocket::Request; + +#[catch(404)] +fn not_found(req: &Request) { /* .. */ } +``` + +Catchers may take zero, one, or two arguments. If the catcher takes one argument, it must be of type [`&Request`](https://api.rocket.rs/v0.5/rocket/struct.Request.html). It it takes two, they must be of type [`Status`](https://api.rocket.rs/v0.5/rocket/http/struct.Status.html) and [`&Request`](https://api.rocket.rs/v0.5/rocket/struct.Request.html), in that order. As with routes, the return type must implement `Responder`. A concrete implementation may look like: + +```rust +#[catch(404)] +fn not_found(req: &Request) -> String { + format!("Sorry, '{}' is not a valid path.", req.uri()) +} +``` + +Also as with routes, Rocket needs to know about a catcher before it is used to handle errors. The process, known as "registering" a catcher, is similar to mounting a route: call the [`register()`](https://api.rocket.rs/v0.5/rocket/struct.Rocket.html#method.register) method with a list of catchers via the [`catchers!`](https://api.rocket.rs/v0.5/rocket/macro.catchers.html) macro. The invocation to add the **404** catcher declared above looks like: + +```rust +fn main() { + rocket::build().register("/", catchers![not_found]); +} +``` + +#### Scoping +The first argument to `register()` is a path to scope the catcher under called the catcher's _base_. A catcher's base determines which requests it will handle errors for. Specifically, a catcher's base must be a prefix of the erroring request for it to be invoked. When multiple catchers can be invoked, the catcher with the longest base takes precedence. + +As an example, consider the following application: + +```rust +#[catch(404)] +fn general_not_found() -> &'static str { + "General 404" +} + +#[catch(404)] +fn foo_not_found() -> &'static str { + "Foo 404" +} + +#[launch] +fn rocket() -> _ { + rocket::build() + .register("/", catchers![general_not_found]) + .register("/foo", catchers![foo_not_found]) +} +``` + +Since there are no mounted routes, all requests will `404`. Any request whose path begins with `/foo` (i.e, `GET /foo`, `GET /foo/bar`, etc) will be handled by the `foo_not_found` catcher while all other requests will be handled by the `general_not_found` catcher. + +#### Default Catchers +A _default_ catcher is a catcher that handles _all_ status codes. They are invoked as a fallback if no status-specific catcher is registered for a given error. Declaring a default catcher is done with `#[catch(default)]` and must similarly be registered with [`register()`](https://api.rocket.rs/v0.5/rocket/struct.Rocket.html#method.register): + +```rust +use rocket::Request; +use rocket::http::Status; + +#[catch(default)] +fn default_catcher(status: Status, request: &Request) { /* .. */ } + +#[launch] +fn rocket() -> _ { + rocket::build().register("/", catchers![default_catcher]) +} +``` + +Catchers with longer bases are preferred, even when there is a status-specific catcher. In other words, a default catcher with a longer matching base than a status-specific catcher takes precedence. + +#### Built-In Catcher +Rocket provides a built-in default catcher. It produces [HTML](../../../internet/HTML.md) or [JSON](../../../files/JSON.md), depending on the value of the `Accept` header. As such, custom catchers only need to be registered for custom error handling. + +## Responses +You may have noticed that the return type of a handler appears to be arbitrary, and that's because it is! A value of any type that implements the [`Responder`](https://api.rocket.rs/v0.5/rocket/response/trait.Responder.html) 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. We'll also briefly discuss how to implement your own `Responder`. + +### Responder +Types that implement [`Responder`](https://api.rocket.rs/v0.5/rocket/response/trait.Responder.html) know how to generate a [`Response`](https://api.rocket.rs/v0.5/rocket/response/struct.Response.html) from their values. A `Response` includes an [HTTP](../../../internet/HTTP.md) status, headers, and body. The body may either be _fixed-sized_ or _streaming_. The given `Responder` implementation decides which to use. For instance, `String` uses a fixed-sized body, while `File` uses a streamed response. Responders may dynamically adjust their responses according to the incoming `Request` they are responding to. + +#### Wrapping +Before we describe a few responders, we note that it is typical for responders to _wrap_ other responders. That is, responders can be of the following form, where `R` is some type that implements `Responder`: + +```rust +struct WrappingResponder(R); +``` + +A wrapping responder modifies the response returned by `R` before responding with that same response. For instance, Rocket provides `Responder`s in the [`status` module](https://api.rocket.rs/v0.5/rocket/response/status/) that override the status code of the wrapped `Responder`. As an example, the [`Accepted`](https://api.rocket.rs/v0.5/rocket/response/status/struct.Accepted.html) type sets the status to `202 - Accepted`. It can be used as follows: + +```rust +use rocket::response::status; + +#[post("/")] +fn new(id: usize) -> status::Accepted { + status::Accepted(format!("id: '{}'", id)) +} +``` + +Similarly, the types in the [`content` module](https://api.rocket.rs/v0.5/rocket/response/content/) can be used to override the Content-Type of a response. For instance, to set the Content-Type of `&'static str` to [JSON](../../../files/JSON.md), as well as setting the status code to an arbitrary one like `418 I'm a teapot`, combine [`content::RawJson`] with [`status::Custom`](https://api.rocket.rs/v0.5/rocket/response/status/struct.Custom.html): + +```rust +use rocket::http::Status; +use rocket::response::{content, status}; + +#[get("/")] +fn json() -> status::Custom> { + status::Custom(Status::ImATeapot, content::RawJson("{ \"hi\": \"world\" }")) +} +``` + +#### Errors +Responders may fail instead of generating a response by returning an `Err` with a status code. When this happens, Rocket forwards the request to the [error catcher](https://rocket.rs/guide/v0.5/requests/#error-catchers) for that status code. + +If an error catcher has been registered for the given status code, Rocket will invoke it. The catcher creates and returns a response to the client. If no error catcher has been registered and the error status code is one of the standard [HTTP](../../../internet/HTTP.md) status code, a default error catcher will be used. Default error catchers return an [HTML](../../../internet/HTML.md) page with the status code and description. If there is no catcher for a custom status code, Rocket uses the **500** error catcher to return a response. + +### Custom Responders +The [`Responder`](https://api.rocket.rs/v0.5/rocket/response/trait.Responder.html) trait documentation details how to implement your own custom responders by explicitly implementing the trait. For most use cases, however, Rocket makes it possible to automatically derive an implementation of `Responder`. In particular, if your custom responder wraps an existing responder, headers, or sets a custom status or content-type, `Responder` can be automatically derived: + +```rust +use rocket::http::{Header, ContentType}; + +#[derive(Responder)] +#[response(status = 500, content_type = "json")] +struct MyResponder { + inner: OtherResponder, + // Override the Content-Type declared above. + header: ContentType, + more: Header<'static>, + #[response(ignore)] + unrelated: MyType, +} +``` + +For the example above, Rocket generates a `Responder` implementation that: + +- Set the response's status to `500: Internal Server Error`. +- Sets the Content-Type to `application/json`. +- Adds the headers `self.header` and `self.more` to the response. +- Completes the response using `self.inner`. + +Note that the _first_ field is used as the inner responder while all remaining fields (unless ignored with `#[response(ignore)]`) are added as headers to the response. The optional `#[response]` attribute can be used to customize the status and content-type of the response. Because `ContentType` is itself a header, you can also dynamically set a content-type by simply including a field of type [`ContentType`](https://api.rocket.rs/v0.5/rocket/http/struct.ContentType.html). To set an [HTTP](../../../internet/HTTP.md) status dynamically, leverage the `(Status, R: Responder)` responder: + +```rust +use rocket::http::{Header, Status}; + +#[derive(Responder)] +#[response(content_type = "json")] +struct MyResponder { + inner: (Status, OtherResponder), + some_header: Header<'static>, +} +``` + +You can also use derive `Responder` for `enum`s, allowing dynamic selection of a responder: + +```rust +use rocket::http::{ContentType, Header, Status}; +use rocket::fs::NamedFile; + +#[derive(Responder)] +enum Error { + #[response(status = 500, content_type = "json")] + A(String), + #[response(status = 404)] + B(NamedFile, ContentType), + C { + inner: (Status, Option), + header: ContentType, + } +} +``` + +For more on using the `Responder` derive, including details on how to use the derive to define generic responders, see the [`Responder` derive](https://api.rocket.rs/v0.5/rocket/derive.Responder.html) documentation. + +### Implementations +Rocket implements `Responder` for many types in Rust's standard library including `String`, `&str`, `File`, `Option`, and `Result`. The [`Responder`](https://api.rocket.rs/v0.5/rocket/response/trait.Responder.html) documentation describes these in detail, but we briefly cover a few here. + +#### Strings +The `Responder` implementations for `&str` and `String` are straight-forward: the string is used as a sized body, and the Content-Type of the response is set to `text/plain`. To get a taste for what such a `Responder` implementation looks like, here's the implementation for `String`: + +```rust +use std::io::Cursor; + +use rocket::request::Request; +use rocket::response::{self, Response, Responder}; +use rocket::http::ContentType; + +#[rocket::async_trait] +impl<'r> Responder<'r, 'static> for String { + fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> { + Response::build() + .header(ContentType::Plain) + .sized_body(self.len(), Cursor::new(self)) + .ok() + } +} +``` + +Because of these implementations, you can directly return an `&str` or `String` type from a handler: + +```rust +#[get("/string")] +fn handler() -> &'static str { + "Hello there! I'm a string!" +} +``` + +#### `Option` +`Option` is a _wrapping_ responder: an `Option` can only be returned when `T` implements `Responder`. If the `Option` is `Some`, the wrapped responder is used to respond to the client. Otherwise, an error of **404 - Not Found** is returned to the client. + +This implementation makes `Option` a convenient type to return when it is not known until process-time whether content exists. For example, because of `Option`, we can implement a file server that returns a `200` when a file is found and a `404` when a file is not found in just 4, idiomatic lines: + +```rust +use rocket::fs::NamedFile; + +#[get("/")] +async fn files(file: PathBuf) -> Option { + NamedFile::open(Path::new("static/").join(file)).await.ok() +} +``` + +#### `Result` +`Result` is another _wrapping_ responder: a `Result` can only be returned when `T` implements `Responder` and `E` implements `Responder`. + +The wrapped `Responder` in `Ok` or `Err`, whichever it might be, is used to respond to the client. This means that the responder can be chosen dynamically at run-time, and two different kinds of responses can be used depending on the circumstances. Revisiting our file server, for instance, we might wish to provide more feedback to the user when a file isn't found. We might do this as follows: + +```rust +use rocket::fs::NamedFile; +use rocket::response::status::NotFound; + +#[get("/")] +async fn files(file: PathBuf) -> Result> { + let path = Path::new("static/").join(file); + NamedFile::open(&path).await.map_err(|e| NotFound(e.to_string())) +} +``` + +### Rocket Responders +Some of Rocket's best features are implemented through responders. Among these are: + +- [`NamedFile`](https://api.rocket.rs/v0.5/rocket/fs/struct.NamedFile.html) - Streams a file to the client; automatically sets the Content-Type based on the file's extension. +- [`Redirect`](https://api.rocket.rs/v0.5/rocket/response/struct.Redirect.html) - Redirects the client to a different URI. +- [`content`](https://api.rocket.rs/v0.5/rocket/response/content/) - Contains types that override the Content-Type of a response. +- [`status`](https://api.rocket.rs/v0.5/rocket/http/struct.Status.html) - Contains types that override the status code of a response. +- [`Flash`](https://api.rocket.rs/v0.5/rocket/response/struct.Flash.html) - Sets a "flash" [cookie](../../../internet/Cookie.md) that is removed when accessed. +- [`Json`](https://api.rocket.rs/v0.5/rocket/serde/json/struct.Json.html) - Automatically serializes values into [JSON](../../../files/JSON.md). +- [`MsgPack`](https://api.rocket.rs/v0.5/rocket/serde/msgpack/struct.MsgPack.html) - Automatically serializes values into [MessagePack](../../../files/MessagePack.md). +- [`Template`](https://api.rocket.rs/v0.5/rocket_dyn_templates/struct.Template.html) - Renders a dynamic template using handlebars or Tera. + +#### Async Streams +The [`stream`](https://api.rocket.rs/v0.5/rocket/response/stream/index.html) responders allow serving potentially infinite [async `Stream`](https://docs.rs/futures/0.3/futures/stream/trait.Stream.html)s. A stream can be created from any async `Stream` or `AsyncRead` type, or via generator syntax using the [`stream!`](https://api.rocket.rs/v0.5/rocket/response/stream/macro.stream.html) macro and its typed equivalents. Streams are the building blocks for unidirectional real-time communication. For instance, the [`chat` example](https://github.com/rwf2/Rocket/tree/v0.5/examples/chat) uses an [`EventStream`](https://api.rocket.rs/v0.5/rocket/response/stream/struct.EventStream.html) to implement a real-time, multi-room chat application using Server-Sent Events (SSE). + +The simplest version creates a [`ReaderStream`](https://api.rocket.rs/v0.5/rocket/response/stream/struct.ReaderStream.html) from a single `AsyncRead` type. For example, to stream from a TCP connection, we might write: + +```rust +use std::io; +use std::net::SocketAddr; + +use rocket::tokio::net::TcpStream; +use rocket::response::stream::ReaderStream; + +#[get("/stream")] +async fn stream() -> io::Result { + let addr = SocketAddr::from(([127, 0, 0, 1], 9999)); + let stream = TcpStream::connect(addr).await?; + Ok(ReaderStream::one(stream)) +} +``` + +Streams can also be created using generator syntax. The following example returns an infinite [`TextStream`](https://api.rocket.rs/v0.5/rocket/response/stream/struct.TextStream.html) that produces one `"hello"` every second: + +```rust +use rocket::tokio::time::{Duration, interval}; +use rocket::response::stream::TextStream; + +/// Produce an infinite series of `"hello"`s, one per second. +#[get("/infinite-hellos")] +fn hello() -> TextStream![&'static str] { + TextStream! { + let mut interval = interval(Duration::from_secs(1)); + loop { + yield "hello"; + interval.tick().await; + } + } +} +``` + +See the [`stream`](https://api.rocket.rs/v0.5/rocket/response/stream/index.html) docs for full details on creating streams including notes on how to detect and handle graceful shutdown requests. + +#### WebSockets +Enabled by Rocket's support for [HTTP connection upgrades](https://api.rocket.rs/v0.5/rocket/response/struct.Response.html#upgrading), the official [`rocket_ws`](https://api.rocket.rs/v0.5/rocket_ws/) crate implements first-class support for WebSockets. Working with `rocket_ws` to implement an echo server looks like this: + +```rust +use rocket_ws::{WebSocket, Stream}; + +#[get("/echo")] +fn echo_compose(ws: WebSocket) -> Stream!['static] { + ws.stream(|io| io) +} +``` + +As with `async` streams, `rocket_ws` also supports using generator syntax for [WebSocket](../../../internet/WebSocket.md) messages: + +```rust +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`](https://api.rocket.rs/v0.5/rocket_ws/) documentation. + +#### JSON +The [`Json`](https://api.rocket.rs/v0.5/rocket/serde/json/struct.Json.html) responder in allows you to easily respond with well-formed [JSON](../../../files/JSON.md) data: simply return a value of type `Json` where `T` is the type of a structure to serialize into [JSON](../../../files/JSON.md). The type `T` must implement the [`Serialize`](https://docs.serde.rs/serde/trait.Serialize.html) trait from [`serde`](https://serde.rs/), which can be automatically derived. + +As an example, to respond with the [JSON](../../../files/JSON.md) value of a `Task` structure, we might write: + +```rust +use rocket::serde::{Serialize, json::Json}; + +#[derive(Serialize)] +#[serde(crate = "rocket::serde")] +struct Task { /* .. */ } + +#[get("/todo")] +fn todo() -> Json { + Json(Task { /* .. */ }) +} +``` + +> You must enable Rocket's `json` crate feature to use the [`Json`](https://api.rocket.rs/v0.5/rocket/serde/json/struct.Json.html) type. + +### Templates +Rocket has first-class templating support that works largely through a [`Template`](https://api.rocket.rs/v0.5/rocket_dyn_templates/struct.Template.html) responder in the `rocket_dyn_templates` contrib library. To render a template named "index", for instance, you might return a value of type `Template` as follows: + +```rust +use rocket_dyn_templates::Template; + +#[get("/")] +fn index() -> Template { + let context = /* object-like value */; + Template::render("index", &context) +} +``` + +Templates are rendered with the `render` method. The method takes in the name of a template and a context to render the template with. The context can be any type that implements `Serialize` and serializes into an `Object` value, such as structs, `HashMaps`, and others. + +You can also use [`context!`](https://api.rocket.rs/v0.5/rocket_dyn_templates/macro.context.html) to create ad-hoc templating contexts without defining a new type: + +```rust +use rocket_dyn_templates::Template; + +#[get("/")] +fn index() -> Template { + Template::render("index", context! { + foo: 123, + }) +} +``` + +To render a template, it must first be registered. The `Template` fairing automatically registers all discoverable templates when attached. The [Fairings](https://rocket.rs/guide/v0.5/fairings/) sections of the guide provides more information on fairings. To attach the template fairing, simply call `.attach(Template::fairing())` on an instance of `Rocket` as follows: + +```rust +use rocket_dyn_templates::Template; + +#[launch] +fn rocket() -> _ { + rocket::build() + .mount("/", routes![/* .. */]) + .attach(Template::fairing()) +} +``` + +Rocket discovers templates in the [configurable](https://rocket.rs/guide/v0.5/configuration/) `template_dir` directory. Templating support in Rocket is engine agnostic. The engine used to render a template depends on the template file's extension. For example, if a file ends with `.hbs`, Handlebars is used, while if a file ends with `.tera`, Tera is used. + + +#### Live Reloading +When your application is compiled in `debug` mode (without the `--release` flag passed to `cargo`), templates are automatically reloaded when they are modified on supported platforms. This means that you don't need to rebuild your application to observe template changes: simply refresh! In release builds, reloading is disabled. + +### Typed URIs +Rocket's [`uri!`](https://api.rocket.rs/v0.5/rocket/macro.uri.html) macro allows you to build URIs to routes in your application 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. + +The `uri!` macro returns an [`Origin`](https://api.rocket.rs/v0.5/rocket/http/uri/struct.Origin.html) structure with the URI of the supplied route interpolated with the given values. Each value passed into `uri!` is rendered in its appropriate place in the URI using the [`UriDisplay`](https://api.rocket.rs/v0.5/rocket/http/uri/fmt/trait.UriDisplay.html) implementation for the value's type. The `UriDisplay` implementation ensures that the rendered value is URI-safe. + +Note that `Origin` implements `Into` (and by extension, `TryInto`), so it can be converted into a [`Uri`](https://api.rocket.rs/v0.5/rocket/http/uri/enum.Uri.html) using `.into()` as needed and passed into methods such as [`Redirect::to()`](https://api.rocket.rs/v0.5/rocket/response/struct.Redirect.html#method.to). + +For example, given the following route: + +```rust +#[get("//?")] +fn person(id: Option, name: &str, age: Option) { /* .. */ } +``` + +URIs to `person` can be created as follows: + +```rust +// with unnamed parameters, in route path declaration order +let mike = uri!(person(101, "Mike Smith", Some(28))); +assert_eq!(mike.to_string(), "/101/Mike%20Smith?age=28"); + +// with named parameters, order irrelevant +let mike = uri!(person(name = "Mike", id = 101, age = Some(28))); +assert_eq!(mike.to_string(), "/101/Mike?age=28"); +let mike = uri!(person(id = 101, age = Some(28), name = "Mike")); +assert_eq!(mike.to_string(), "/101/Mike?age=28"); + +// with a specific mount-point +let mike = uri!("/api", person(id = 101, name = "Mike", age = Some(28))); +assert_eq!(mike.to_string(), "/api/101/Mike?age=28"); + +// with optional (defaultable) query parameters ignored +let mike = uri!(person(101, "Mike", _)); +assert_eq!(mike.to_string(), "/101/Mike"); +let mike = uri!(person(id = 101, name = "Mike", age = _)); +assert_eq!(mike.to_string(), "/101/Mike"); +``` + +Rocket informs you of any mismatched parameters at compile-time: + +``` +error: `person` route uri expects 3 parameters but 1 was supplied + --> examples/uri/main.rs:7:26 + | +7 | let x = uri!(person("Mike Smith")); + | ^^^^^^^^^^^^ + | + = note: expected parameters: id: Option , name: &str, age: Option +``` + +Rocket also informs you of any type errors at compile-time: + +``` + --> examples/uri/src/main.rs:7:31 + | +7 | let x = uri!(person(id = "10", name = "Mike Smith", age = Some(10))); + | ^^^^ `FromUriParam` is not implemented for `usize` +``` + +We recommend that you use `uri!` exclusively when constructing URIs to your routes. + +#### Ignorables +As illustrated in the previous above, query parameters can be ignored using `_` in place of an expression in a `uri!` invocation. The corresponding type in the route URI must implement [`Ignorable`](https://api.rocket.rs/v0.5/rocket/http/uri/fmt/trait.Ignorable.html). Ignored parameters are not interpolated into the resulting `Origin`. Path parameters are not ignorable. + +#### Deriving`UriDisplay` +The `UriDisplay` trait can be derived for custom types. For types that appear in the path part of a URI, derive using [`UriDisplayPath`](https://api.rocket.rs/v0.5/rocket/derive.UriDisplayPath.html); for types that appear in the query part of a URI, derive using [`UriDisplayQuery`](https://api.rocket.rs/v0.5/rocket/derive.UriDisplayQuery.html). + +As an example, consider the following form structure and route: + +```rust +use rocket::form::Form; + +#[derive(FromForm, UriDisplayQuery)] +struct UserDetails<'r> { + age: Option, + nickname: &'r str, +} + +#[post("/user/?")] +fn add_user(id: usize, details: UserDetails) { /* .. */ } +``` + +By deriving using `UriDisplayQuery`, an implementation of `UriDisplay` is automatically generated, allowing for URIs to `add_user` to be generated using `uri!`: + +```rust +let link = uri!(add_user(120, UserDetails { age: Some(20), nickname: "Bob".into() })); +assert_eq!(link.to_string(), "/user/120?age=20&nickname=Bob"); +``` + +## State +Many web applications have a need to maintain state. This can be as simple as maintaining a counter for the number of visits or as complex as needing to access job queues and multiple databases. Rocket provides the tools to enable these kinds of interactions in a safe and simple manner. + +### Managed State +The enabling feature for maintaining state is _managed state_. Managed state, as the name implies, is state that Rocket manages for your application. The state is managed on a per-type basis: Rocket will manage at most one value of a given type. + +The process for using managed state is simple: + +1. Call `manage` on the `Rocket` instance corresponding to your application with the initial value of the state. +2. Add a `&State` type to any request handler, where `T` is the type of the value passed into `manage`. + +> All managed state must be thread-safe. + +Because Rocket automatically parallelizes your application, handlers can concurrently access managed state. As a result, managed state must be thread-safe. Thanks to [Rust](../languages/Rust.md), this condition is checked at compile-time by ensuring that the type of values you store in managed state implement `Send` + `Sync`. + +#### Adding State +To instruct Rocket to manage state for your application, call the [`manage`](https://api.rocket.rs/v0.5/rocket/struct.Rocket.html#method.manage) method 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 write the following: + +```rust +use std::sync::atomic::AtomicUsize; + +struct HitCount { + count: AtomicUsize +} + +rocket::build().manage(HitCount { count: AtomicUsize::new(0) }); +``` + +The `manage` method can be called any number of times as long as each call refers to a value of a different type. For instance, to have Rocket manage both a `HitCount` value and a `Config` value, we can write: + +```rust +rocket::build() + .manage(HitCount { count: AtomicUsize::new(0) }) + .manage(Config::from(user_input)); +``` + +#### Retrieving State +State that is being managed by Rocket can be retrieved via the [`&State`](https://api.rocket.rs/v0.5/rocket/struct.State.html) type: a [request guard](https://rocket.rs/guide/v0.5/requests/#request-guards) for managed state. To use the request guard, add a `&State` type to any request handler, where `T` is the type of the managed state. For example, we can retrieve and respond with the current `HitCount` in a `count` route as follows: + +```rust +use rocket::State; + +#[get("/count")] +fn count(hit_count: &State) -> String { + let current_count = hit_count.count.load(Ordering::Relaxed); + format!("Number of visits: {}", current_count) +} +``` + +You can retrieve more than one `&State` type in a single route as well: + +```rust +#[get("/state")] +fn state(hit_count: &State, config: &State) { /* .. */ } +``` + +> If you request a `&State` for a `T` that is not `managed`, Rocket will refuse to start your application. This prevents what would have been an unmanaged state runtime error. Unmanaged state is detected at runtime through [_sentinels_](https://api.rocket.rs/v0.5/rocket/trait.Sentinel.html), so there are limitations. If a 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. + + +#### Within Guards +Because `State` is itself a request guard, managed state can be retrieved from another request guard's implementation using either [`Request::guard()`](https://api.rocket.rs/v0.5/rocket/struct.Request.html#method.guard) or [`Rocket::state()`](https://api.rocket.rs/v0.5/rocket/struct.Rocket.html#method.state). In the following code example, the `Item` request guard retrieves `MyConfig` from managed state using both methods: + +```rust +use rocket::State; +use rocket::request::{self, Request, FromRequest}; +use rocket::outcome::IntoOutcome; +use rocket::http::Status; + +struct Item<'r>(&'r str); + +#[rocket::async_trait] +impl<'r> FromRequest<'r> for Item<'r> { + type Error = (); + + async fn from_request(request: &'r Request<'_>) -> request::Outcome { + // Using `State` as a request guard. Use `inner()` to get an `'r`. + let outcome = request.guard::<&State>().await + .map(|my_config| Item(&my_config.user_val)); + + // Or alternatively, using `Rocket::state()`: + let outcome = request.rocket().state::() + .map(|my_config| Item(&my_config.user_val)) + .or_forward(Status::InternalServerError); + + outcome + } +} +``` + +## Fairings +Fairings are Rocket's approach to structured middleware. With fairings, your application can hook into the request lifecycle to record or rewrite information about incoming requests and outgoing responses. + +### Overview +Any type that implements the [`Fairing`](https://api.rocket.rs/v0.5/rocket/fairing/trait.Fairing.html) trait is a _fairing_. Fairings hook into Rocket's request lifecycle, receiving callbacks for events such as incoming requests and outgoing responses. Rocket passes information about these events to the fairing; the fairing can do what it wants with the information. This includes rewriting requests or responses, recording information about the event, or doing nothing at all. + +Rocket’s fairings are a lot like middleware from other frameworks, but they bear a few key distinctions: + +- Fairings **cannot** terminate or respond to an incoming request directly. +- 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. + +If you are familiar with middleware from other frameworks, you may find yourself reaching for fairings instinctively. Before doing so, remember that Rocket provides a rich set of mechanisms such as [request guards](https://rocket.rs/guide/v0.5/requests/#request-guards) and [data guards](https://rocket.rs/guide/v0.5/requests/#body-data) that can be used to solve problems in a clean, composable, and robust manner. + +As a general rule of thumb, only _globally applicable_ actions should be effected through fairings. You should **_not_** use a fairing to implement authentication or authorization (preferring to use a [request guard](https://rocket.rs/guide/v0.5/requests/#request-guards) instead) _unless_ the authentication or authorization applies to all or the overwhelming majority of the application. On the other hand, you _should_ use a fairing to record timing and usage statistics or to enforce global security policies. + +#### Attaching +Fairings are registered with Rocket via the [`attach`](https://api.rocket.rs/v0.5/rocket/struct.Rocket.html#method.attach) method on a [`Rocket`](https://api.rocket.rs/v0.5/rocket/struct.Rocket.html) instance. Only when a fairing is attached will its callbacks fire. As an example, the following snippet attached two fairings, `req_fairing` and `res_fairing`, to a new Rocket instance: + +```rust +#[launch] +fn rocket() -> _ { + rocket::build() + .attach(req_fairing) + .attach(res_fairing) +} +``` + +Fairings are executed in the order in which they are attached: the first attached fairing has its callbacks executed before all others. A fairing can be attached any number of times. Except for [singleton fairings](https://api.rocket.rs/v0.5/rocket/fairing/trait.Fairing.html#singletons), all attached instances are polled at runtime. Fairing callbacks may not be commutative; the order in which fairings are attached may be significant. + +#### Callbacks +There are five events for which Rocket issues fairing callbacks. Each of these events is briefly described below and in details in the [`Fairing`](https://api.rocket.rs/v0.5/rocket/fairing/trait.Fairing.html) trait docs: + +- **Ignite (`on_ignite`)** + + An ignite callback is called during [ignition](https://api.rocket.rs/v0.5/rocket/struct.Rocket.html#method.ignite) An ignite callback can arbitrarily modify the `Rocket` instance being built. They are commonly used to parse and validate configuration values, aborting on bad configurations, and inserting the parsed value into managed state for later retrieval. + +- **Liftoff (`on_liftoff`)** + + A liftoff callback is called immediately after a Rocket application has launched. A liftoff callback can inspect the `Rocket` instance being launched. A liftoff callback can be a convenient hook for launching services related to the Rocket application being launched. + +- **Request (`on_request`)** + + A request callback is called just after a request is received. A request callback can modify the request at will and peek into the incoming data. It may not, however, abort or respond directly to the request; these issues are better handled via request guards or via response callbacks. + +- **Response (`on_response`)** + + A response callback is called when a response is ready to be sent to the client. A response callback can modify part or all of the response. As such, a response fairing can be used to provide a response when the greater application fails by rewriting **404** responses as desired. As another example, response fairings can also be used to inject headers into all outgoing responses. + +- **Shutdown (`on_shutdown`)** + + A shutdown callback is called when [shutdown is triggered](https://api.rocket.rs/v0.5/rocket/config/struct.Shutdown.html#triggers). At this point, graceful shutdown has commenced but not completed; no new requests are accepted but the application may still be actively serving existing requests. All registered shutdown fairings are run concurrently; resolution of all fairings is awaited before resuming shutdown. + + +### Implementing +Recall that a fairing is any type that implements the [`Fairing`](https://api.rocket.rs/v0.5/rocket/fairing/trait.Fairing.html) trait. A `Fairing` implementation has one required method: [`info`](https://api.rocket.rs/v0.5/rocket/fairing/struct.Info.html), which returns an [`Info`](https://api.rocket.rs/v0.5/rocket/fairing/struct.Info.html) structure. This structure is used by Rocket to assign a name to the fairing and determine the set of callbacks the fairing is registering for. A `Fairing` can implement any of the available callbacks: [`on_ignite`](https://api.rocket.rs/v0.5/rocket/fairing/trait.Fairing.html#method.on_ignite), [`on_liftoff`](https://api.rocket.rs/v0.5/rocket/fairing/trait.Fairing.html#method.on_liftoff), [`on_request`](https://api.rocket.rs/v0.5/rocket/fairing/trait.Fairing.html#method.on_request), [`on_response`](https://api.rocket.rs/v0.5/rocket/fairing/trait.Fairing.html#method.on_response), and [`on_shutdown`](https://api.rocket.rs/v0.5/rocket/fairing/trait.Fairing.html#method.on_shutdown). Each callback has a default implementation that does absolutely nothing. + +#### Requirements +A type implementing `Fairing` is required to be `Send + Sync + 'static`. This means that the fairing must be sendable across thread boundaries (`Send`), thread-safe (`Sync`), and have only static references, if any (`'static`). Note that these bounds _do not_ prohibit a `Fairing` from holding state: the state need simply be thread-safe and statically available or heap allocated. + +#### Example +As an example, we want to record the number of `GET` and `POST` requests that our application has received. While we could do this with request guards and managed state, it would require us to annotate every `GET` and `POST` request with custom types, polluting handler signatures. Instead, we can create a simple fairing that acts globally. + +The code for a `Counter` fairing below implements exactly this. The fairing receives a request callback, where it increments a counter on each `GET` and `POST` request. It also receives a response callback, where it responds to unrouted requests to the `/counts` path by returning the recorded number of counts. + +```rust +use std::io::Cursor; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use rocket::{Request, Data, Response}; +use rocket::fairing::{Fairing, Info, Kind}; +use rocket::http::{Method, ContentType, Status}; + +struct Counter { + get: AtomicUsize, + post: AtomicUsize, +} + +#[rocket::async_trait] +impl Fairing for Counter { + // This is a request and response fairing named "GET/POST Counter". + fn info(&self) -> Info { + Info { + name: "GET/POST Counter", + kind: Kind::Request | Kind::Response + } + } + + // Increment the counter for `GET` and `POST` requests. + async fn on_request(&self, request: &mut Request<'_>, _: &mut Data<'_>) { + match request.method() { + Method::Get => self.get.fetch_add(1, Ordering::Relaxed), + Method::Post => self.post.fetch_add(1, Ordering::Relaxed), + _ => return + }; + } + + async fn on_response<'r>(&self, request: &'r Request<'_>, response: &mut Response<'r>) { + // Don't change a successful user's response, ever. + if response.status() != Status::NotFound { + return + } + + // Rewrite the response to return the current counts. + if request.method() == Method::Get && request.uri().path() == "/counts" { + let get_count = self.get.load(Ordering::Relaxed); + let post_count = self.post.load(Ordering::Relaxed); + let body = format!("Get: {}\nPost: {}", get_count, post_count); + + response.set_status(Status::Ok); + response.set_header(ContentType::Plain); + response.set_sized_body(body.len(), Cursor::new(body)); + } + } +} +``` + +The complete example can be found in the [`Fairing` documentation](https://api.rocket.rs/v0.5/rocket/fairing/trait.Fairing.html#example). + +### Ad-Hoc Fairings +For simpler cases, implementing the `Fairing` trait can be cumbersome. This is why Rocket provides the [`AdHoc`](https://api.rocket.rs/v0.5/rocket/fairing/struct.AdHoc.html) type, which creates a fairing from a simple function or closure. Using the `AdHoc` type is easy: simply call the `on_ignite`, `on_liftoff`, `on_request`, `on_response`, or `on_shutdown` constructors on `AdHoc` to create a fairing from a function or closure. + +As an example, the code below creates a `Rocket` instance with two attached ad-hoc fairings. The first, a liftoff fairing named "Liftoff Printer", prints a message indicating that the application has launched. The second named "Put Rewriter", a request fairing, rewrites the method of all requests to be `PUT`. + +```rust +use rocket::fairing::AdHoc; +use rocket::http::Method; + +rocket::build() + .attach(AdHoc::on_liftoff("Liftoff Printer", |_| Box::pin(async move { + println!("...annnddd we have liftoff!"); + }))) + .attach(AdHoc::on_request("Put Rewriter", |req, _| Box::pin(async move { + req.set_method(Method::Put); + }))) + .attach(AdHoc::on_shutdown("Shutdown Printer", |_| Box::pin(async move { + println!("...shutdown has commenced!"); + }))); +``` + +## Configuration +Rocket's configuration system is flexible. Based on [Figment](https://docs.rs/figment/0.10/figment), it allows you to configure your application the way _you_ want while also providing with a sensible set of defaults. + +### Overview +Rocket's configuration system is based on Figment's [`Provider`](https://docs.rs/figment/0.10/figment/trait.Provider.html)s, types which provide configuration data. Rocket's [`Config`](https://api.rocket.rs/v0.5/rocket/struct.Config.html) and [`Config::figment()`](https://api.rocket.rs/v0.5/rocket/struct.Config.html#method.figment), as well as Figment's [`Toml`](https://docs.rs/figment/0.10/figment/providers/struct.Toml.html) and [`Json`](https://docs.rs/figment/0.10/figment/providers/struct.Json.html), are some examples of providers. Providers can be combined into a single [`Figment`](https://docs.rs/figment/0.10/figment/struct.Figment.html) provider from which any configuration structure that implements [`Deserialize`](https://api.rocket.rs/v0.5/rocket/serde/trait.Deserialize.html) can be extracted. + +Rocket expects to be able to extract a [`Config`](https://api.rocket.rs/v0.5/rocket/struct.Config.html) structure from the provider it is configured with. This means that no matter which configuration provider Rocket is asked to use, it must be able to read the following configuration values: + +| key | kind | description | debug/release default | +| --------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| `address` | `IpAddr` | [IP](../../../internet/Internet%20Protocol.md) address to serve on | `127.0.0.1` | +| `port` | `u16` | Port to serve on. | `8000` | +| `workers`* | `usize` | Number of threads to use for executing futures. | cpu core count | +| `max_blocking`* | `usize` | Limit on threads to start for blocking tasks. | `512` | +| `ident` | `string`, `false` | If and how to identify via the `Server` header. | `"Rocket"` | +| `ip_header` | `string`, `false` | IP header to inspect to get [client's real IP](https://api.rocket.rs/v0.5/rocket/request/struct.Request.html#method.real_ip). | `"X-Real-IP"` | +| `keep_alive` | `u32` | Keep-alive timeout seconds; disabled when `0`. | `5` | +| `log_level` | [`LogLevel`](https://api.rocket.rs/v0.5/rocket/config/enum.LogLevel.html) | Max level to log. (off/normal/debug/critical) | `normal`/`critical` | +| `cli_colors` | `bool` | Whether to use colors and emoji when logging. | `true` | +| `secret_key` | [`SecretKey`](https://api.rocket.rs/v0.5/rocket/config/struct.SecretKey.html) | Secret key for signing and encrypting values. | `None` | +| `tls` | [`TlsConfig`](https://api.rocket.rs/v0.5/rocket/config/struct.TlsConfig.html) | TLS configuration, if any. | `None` | +| `limits` | [`Limits`](https://api.rocket.rs/v0.5/rocket/data/struct.Limits.html) | Streaming read size limits. | [`Limits::default()`](https://api.rocket.rs/v0.5/rocket/data/struct.Limits.html#impl-Default-for-Limits) | +| `limits.$name` | `&str`/`uint` | Read limit for `$name`. | form = "32KiB" | +| `ctrlc` | `bool` | Whether `ctrl-c` initiates a server shutdown. | `true` | +| `shutdown`* | [`Shutdown`](https://api.rocket.rs/v0.5/rocket/config/struct.Shutdown.html) | Graceful shutdown configuration. | [`Shutdown::default()`](https://api.rocket.rs/v0.5/rocket/config/struct.Shutdown.html#fields) | + +* Note: the `workers`, `max_blocking`, and `shutdown.force` configuration parameters are only read from the [default provider](https://rocket.rs/guide/v0.5/configuration/#default-provider). + +### Profiles +Configurations can be arbitrarily namespaced by [`Profile`](https://docs.rs/figment/0.10/figment/struct.Profile.html)s. Rocket's [`Config`](https://api.rocket.rs/v0.5/rocket/struct.Config.html) and [`Config::figment()`](https://api.rocket.rs/v0.5/rocket/struct.Config.html#method.figment) providers automatically set the configuration profile to "debug" when compiled in "debug" mode and "release" when compiled in release mode, but you can arbitrarily name and set profiles to your desire. For example, with the [default provider](https://rocket.rs/guide/v0.5/configuration/#default-provider), you can set the selected profile via `ROCKET_PROFILE`. This results in Rocket preferring the values in the `ROCKET_PROFILE` profile. + +In addition to any profiles you declare, there are two meta-profiles, `default` and `global`, which can be used to provide values that apply to _all_ profiles. Values provided in a `default` profile are used as fall-back values when the selected profile doesn't contain a requested value, while values in the `global` profile supplant any values with the same name in any profile. + +### Default Provider +Rocket's default configuration provider is [`Config::figment()`](https://api.rocket.rs/v0.5/rocket/struct.Config.html#method.figment); this is the provider that's used when calling [`rocket::build()`](https://api.rocket.rs/v0.5/rocket/fn.custom.html). + +The default figment reads from and merges, at a per-key level, the following sources in ascending priority order: + +1. [`Config::default()`](https://api.rocket.rs/v0.5/rocket/struct.Config.html#method.default), which provides default values for all parameters. +2. `Rocket.toml` _or_ TOML file path in `ROCKET_CONFIG` environment variable. +3. `ROCKET_` prefixed environment variables. + +The selected profile is the value of the `ROCKET_PROFILE` environment variable, or if it is not set, "debug" when compiled in debug mode and "release" when compiled in release mode. With the exception of `log_level`, which changes from `normal` in debug to `critical` in release, all of the default configuration values are the same in all profiles. What's more, all configuration values _have_ defaults, so no configuration is needed to get started. + +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 take precedence over the former. + +### Rocket.toml +Rocket searches for `Rocket.toml` or the filename in a `ROCKET_CONFIG` environment variable starting at the current working directory. If it is not found, the parent directory, its parent, and so on, are searched until the file is found or the root is reached. If the path set in `ROCKET_CONFIG` is absolute, no such search occurs and the set path is used directly. + +The file is assumed to be _nested_, so each top-level key declares a profile and its values the value for the profile. The following is an example of what such a file might look like: + +```ini +## defaults for _all_ profiles +[default] +address = "0.0.0.0" +limits = { form = "64 kB", json = "1 MiB" } + +## set only when compiled in debug mode, i.e, `cargo build` +[debug] +port = 8000 +## only the `json` key from `default` will be overridden; `form` will remain +limits = { json = "10MiB" } + +## set only when the `nyc` profile is selected +[nyc] +port = 9001 + +## set only when compiled in release mode, i.e, `cargo build --release` +[release] +port = 9999 +ip_header = false +secret_key = "hPrYyЭRiMyµ5sBB1π+CMæ1køFsåqKvBiQJxBVHQk=" +``` + +The following is a `Rocket.toml` file with all configuration options set for demonstration purposes. You **do not** and _should not_ set a value for configuration options needlessly, preferring to use the default value when sensible. + +```ini +[default] +address = "127.0.0.1" +port = 8000 +workers = 16 +max_blocking = 512 +keep_alive = 5 +ident = "Rocket" +ip_header = "X-Real-IP" # set to `false` to disable +log_level = "normal" +temp_dir = "/tmp" +cli_colors = true +secret_key = "hPrYyЭRiMyµ5sBB1π+CMæ1køFsåqKvBiQJxBVHQk=" + +[default.limits] +form = "64 kB" +json = "1 MiB" +msgpack = "2 MiB" +"file/jpg" = "5 MiB" + +[default.tls] +certs = "path/to/cert-chain.pem" +key = "path/to/key.pem" + +[default.shutdown] +ctrlc = true +signals = ["term", "hup"] +grace = 5 +mercy = 5 +``` + +### Environment Variables +Rocket reads all environment variable names prefixed with `ROCKET_` using the string after the `_` as the name of a configuration value as the value of the parameter as the value itself. [Environment variables](../../../linux/Environment%20Variables.md) take precedence over values in `Rocket.toml`. Values are parsed as loose form of [TOML](../../../files/TOML.md) syntax. Consider the following examples: + +```shell +ROCKET_FLOAT=3.14 +ROCKET_ARRAY=[1,"b",3.14] +ROCKET_STRING=Hello +ROCKET_STRING="Hello There" + +ROCKET_KEEP_ALIVE=1 +ROCKET_IDENT=Rocket +ROCKET_IDENT="Hello Rocket" +ROCKET_IDENT=false +ROCKET_TLS={certs="abc",key="foo/bar"} +ROCKET_LIMITS={form="64 KiB"} +``` + +## Deployment +In a _containerization_ environment, you are responsible for writing a [`Dockerfile`](../../../tools/Dockerfile.md) or `Containerfile` which you provide to an application platform. + +Below you'll find an example of a `Dockerfile` that: + +- Builds the application with the latest stable [Rust](../languages/Rust.md) compiler. +- Uses `--mount=type=cache` to avoid recompiling dependencies. +- Uses a second stage to create a slim (~100MiB), ready-to-deploy image with only what's needed. +- Bundles all of an application's assets in the container. + +```dockerfile +FROM docker.io/rust:1-slim-bookworm AS build + +## cargo package name: customize here or provide via --build-arg +ARG pkg=rocket-app + +WORKDIR /build + +COPY . . + +RUN --mount=type=cache,target=/build/target \ + --mount=type=cache,target=/usr/local/cargo/registry \ + --mount=type=cache,target=/usr/local/cargo/git \ + set -eux; \ + cargo build --release; \ + objcopy --compress-debug-sections target/release/$pkg ./main + +################################################################################ +FROM docker.io/debian:bookworm-slim + +WORKDIR /app + +## copy the main binary +COPY --from=build /build/main ./ + +## copy runtime assets which may or may not exist +COPY --from=build /build/Rocket.tom[l] ./static +COPY --from=build /build/stati[c] ./static +COPY --from=build /build/template[s] ./templates + +## ensure the container listens globally on port 8080 +ENV ROCKET_ADDRESS=0.0.0.0 +ENV ROCKET_PORT=8080 + +CMD ./main +``` + +You will need to modify the `pkg` `ARG` or provide it via the command-line: + +```shell +docker build --build-arg pkg=cargo_package_name -t app . +``` + +You may also need to make the following changes: + +- Add/remove/modify `ENV` variables as needed. +- Modify the expected `target/release/$pkg` directory. +- Add more assets to `COPY` to the final image. + +Finally, we recommend the following `.dockerignore` file to avoid copying unnecessary artifacts: + +``` +target +.cargo +**/*.sh +**/*.tar.gz +```