+++ summary = "generating responses and using typed URIs" +++ # 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`] 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`]: @api/master/rocket/response/trait.Responder.html ## Responder Types that implement [`Responder`] know how to generate a [`Response`] from their values. A `Response` includes an HTTP 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. [`Response`]: @api/master/rocket/response/struct.Response.html ### 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](@api/master/rocket/response/status/) that override the status code of the wrapped `Responder`. As an example, the [`Accepted`] type sets the status to `202 - Accepted`. It can be used as follows: ```rust # #[macro_use] extern crate rocket; # fn main() {} use rocket::response::status; #[post("/")] fn new(id: usize) -> status::Accepted { status::Accepted(format!("id: '{}'", id)) } ``` Similarly, the types in the [`content` module](@api/master/rocket/response/content/) can be used to override the Content-Type of a response. For instance, to set the Content-Type of `&'static str` to JSON, as well as setting the status code to an arbitrary one like `418 I'm a teapot`, combine [`content::RawJson`] with [`status::Custom`]: ```rust # #[macro_use] extern crate rocket; use rocket::http::Status; use rocket::response::{content, status}; #[get("/")] fn json() -> status::Custom> { status::Custom(Status::ImATeapot, content::RawJson("{ \"hi\": \"world\" }")) } ``` ! warning: This is _not_ the same as [`serde::json::Json`]! The built-in `(Status, R)` and `(ContentType, R)` responders, where `R: Responder`, also override the `Status` and `Content-Type` of responses, respectively: ```rust # #[macro_use] extern crate rocket; use rocket::http::{Status, ContentType}; #[get("/")] fn json() -> (Status, (ContentType, &'static str)) { (Status::ImATeapot, (ContentType::JSON, "{ \"hi\": \"world\" }")) } ``` For pithy reusability, it is advisable to derive a [custom responder]: ```rust # #[macro_use] extern crate rocket; #[derive(Responder)] #[response(status = 418, content_type = "json")] struct RawTeapotJson(&'static str); #[get("/")] fn json() -> RawTeapotJson { RawTeapotJson("{ \"hi\": \"world\" }") } ``` [`Accepted`]: @api/master/rocket/response/status/struct.Accepted.html [`content::Json`]: @api/master/rocket/response/content/struct.Json.html [`status::Custom`]: @api/master/rocket/response/status/struct.Custom.html [`serde::json::Json`]: @api/master/rocket/serde/json/struct.Json.html [custom responder]: #custom-responders ### 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](../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 status code, a default error catcher will be used. Default error catchers return an HTML 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. ### Status While not encouraged, you can also forward a request to a catcher manually by returning a [`Status`] directly. For instance, to forward to the catcher for **406: Not Acceptable**, you would write: ```rust # #[macro_use] extern crate rocket; # fn main() {} use rocket::http::Status; #[get("/")] fn just_fail() -> Status { Status::NotAcceptable } ``` The response generated by `Status` depends on the status code itself. As indicated above, for error status codes (in range [400, 599]), `Status` forwards to the corresponding error catcher. The table below summarizes responses generated by `Status` for these and other codes: | Status Code Range | Response | |-------------------|---------------------------------------| | [400, 599] | Forwards to catcher for given status. | | 100, [200, 205] | Empty with given status. | | All others. | Invalid. Errors to `500` catcher. | [`Status`]: @api/master/rocket/http/struct.Status.html ## Custom Responders The [`Responder`] 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 # #[macro_use] extern crate rocket; # fn main() {} use rocket::http::{Header, ContentType}; # type OtherResponder = (); # type MyType = u8; #[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`]. To set an HTTP status dynamically, leverage the `(Status, R: Responder)` responder: ```rust # #[macro_use] extern crate rocket; # fn main() {} use rocket::http::{Header, Status}; # type OtherResponder = (); #[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 # #[macro_use] extern crate rocket; # fn main() {} 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] documentation. [`Responder` derive]: @api/master/rocket/derive.Responder.html [`ContentType`]: @api/master/rocket/http/struct.ContentType.html ## Implementations Rocket implements `Responder` for many types in Rust's standard library including `String`, `&str`, `File`, `Option`, and `Result`. The [`Responder`] documentation describes these in detail, but we briefly cover a few here. ### 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 # #[macro_use] extern crate rocket; # fn main() {} use std::io::Cursor; use rocket::request::Request; use rocket::response::{self, Response, Responder}; use rocket::http::ContentType; # struct String(std::string::String); #[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)) # */ # .sized_body(self.0.len(), Cursor::new(self.0)) .ok() } } ``` Because of these implementations, you can directly return an `&str` or `String` type from a handler: ```rust # #[macro_use] extern crate rocket; # fn main() {} #[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 # #[macro_use] extern crate rocket; # fn main() {} # 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() } ``` ### `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 # #[macro_use] extern crate rocket; # fn main() {} # use std::path::{Path, PathBuf}; 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`] - Streams a file to the client; automatically sets the Content-Type based on the file's extension. * [`Redirect`] - Redirects the client to a different URI. * [`content`] - Contains types that override the Content-Type of a response. * [`status`] - Contains types that override the status code of a response. * [`Flash`] - Sets a "flash" cookie that is removed when accessed. * [`Json`] - Automatically serializes values into JSON. * [`MsgPack`] - Automatically serializes values into MessagePack. * [`Template`] - Renders a dynamic template using handlebars or Tera. [`status`]: @api/master/rocket/response/status/ [`content`]: @api/master/rocket/response/content/ [`response`]: @api/master/rocket/response/ [`NamedFile`]: @api/master/rocket/fs/struct.NamedFile.html [`Redirect`]: @api/master/rocket/response/struct.Redirect.html [`Flash`]: @api/master/rocket/response/struct.Flash.html [`MsgPack`]: @api/master/rocket/serde/msgpack/struct.MsgPack.html [`Template`]: @api/master/rocket_dyn_templates/struct.Template.html ### Async Streams The [`stream`] responders allow serving potentially infinite [async `Stream`]s. A stream can be created from any async `Stream` or `AsyncRead` type, or via generator syntax using the [`stream!`] macro and its typed equivalents. Streams are the building blocks for unidirectional real-time communication. For instance, the [`chat` example] uses an [`EventStream`] to implement a real-time, multi-room chat application using Server-Sent Events (SSE). The simplest version creates a [`ReaderStream`] from a single `AsyncRead` type. For example, to stream from a TCP connection, we might write: ```rust # use rocket::*; 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`] that produces one `"hello"` every second: ```rust # use rocket::get; 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`] docs for full details on creating streams including notes on how to detect and handle graceful shutdown requests. [`stream`]: @api/master/rocket/response/stream/index.html [`stream!`]: @api/master/rocket/response/stream/macro.stream.html [async `Stream`]: https://docs.rs/futures/0.3/futures/stream/trait.Stream.html [`ReaderStream`]: @api/master/rocket/response/stream/struct.ReaderStream.html [`TextStream`]: @api/master/rocket/response/stream/struct.TextStream.html [`EventStream`]: @api/master/rocket/response/stream/struct.EventStream.html [`chat` example]: @git/master/examples/chat ### WebSockets Enabled by Rocket's support for [HTTP connection upgrades], the official [`rocket_ws`] crate implements first-class support for WebSockets. Working with `rocket_ws` to implement an echo server looks like this: ```rust # use rocket::get; use rocket_ws::{WebSocket, Stream}; #[get("/echo")] fn echo_compose(ws: WebSocket) -> Stream!['static] { ws.stream(|io| io) } ``` As with `async` streams, `rocket_ws` also supports using generator syntax for WebSocket messages: ```rust # use rocket::get; use rocket_ws::{WebSocket, Stream}; #[get("/echo")] fn echo_stream(ws: WebSocket) -> Stream!['static] { Stream! { ws => for await message in ws { yield message?; } } } ``` For complete usage details, see the [`rocket_ws`] documentation. [HTTP connection upgrades]: @api/master/rocket/response/struct.Response.html#upgrading [`rocket_ws`]: @api/master/rocket_ws/ ### JSON The [`Json`] responder in allows you to easily respond with well-formed JSON data: simply return a value of type `Json` where `T` is the type of a structure to serialize into JSON. The type `T` must implement the [`Serialize`] trait from [`serde`], which can be automatically derived. As an example, to respond with the JSON value of a `Task` structure, we might write: ```rust # #[macro_use] extern crate rocket; use rocket::serde::{Serialize, json::Json}; #[derive(Serialize)] #[serde(crate = "rocket::serde")] struct Task { /* .. */ } #[get("/todo")] fn todo() -> Json { Json(Task { /* .. */ }) } ``` ! note: You must enable Rocket's `json` crate feature to use the [`Json`] type. The `Json` type serializes the structure into JSON, sets the Content-Type to JSON, and emits the serialized data in a fixed-sized body. If serialization fails, a **500 - Internal Server Error** is returned. The [serialization example] provides further illustration. [`Json`]: @api/master/rocket/serde/json/struct.Json.html [`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html [`serde`]: https://serde.rs [serialization example]: @git/master/examples/serialization ## Templates Rocket has first-class templating support that works largely through a [`Template`] 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 # #[macro_use] extern crate rocket; # fn main() {} use rocket_dyn_templates::Template; #[get("/")] fn index() -> Template { # /* let context = /* object-like value */; # */ let context = (); 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!`] to create ad-hoc templating contexts without defining a new type: ```rust # #[macro_use] extern crate rocket; # #[macro_use] extern crate rocket_dyn_templates; # fn main() {} 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](../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 # #[macro_use] extern crate rocket; use rocket_dyn_templates::Template; #[launch] fn rocket() -> _ { rocket::build() .mount("/", routes![/* .. */]) .attach(Template::fairing()) } ``` Rocket discovers templates in the [configurable] `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. ! note: The name of the template _does not_ include its extension. For a template file named `index.html.tera`, call `render("index")` and use the name `"index"` in templates, i.e, `extends "index"` or `extends "base"` for `base.html.tera`. [`context!`]: @api/master/rocket_dyn_templates/macro.context.html ### 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. The [`Template`] API documentation contains more information about templates, including how to customize a template engine to add custom helpers and filters. The [templating example](@git/master/examples/templating) uses both Tera and Handlebars templating to implement the same application. [configurable]: ../configuration/ ## Typed URIs Rocket's [`uri!`] 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`] 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`] 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`] using `.into()` as needed and passed into methods such as [`Redirect::to()`]. For example, given the following route: ```rust # #[macro_use] extern crate rocket; # fn main() {} #[get("//?")] fn person(id: Option, name: &str, age: Option) { /* .. */ } ``` URIs to `person` can be created as follows: ```rust # #[macro_use] extern crate rocket; # #[get("//?")] # fn person(id: Option, name: &str, age: Option) { /* .. */ } // 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: ```rust,ignore 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: ```rust,ignore --> 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`]. 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`]; for types that appear in the query part of a URI, derive using [`UriDisplayQuery`]. As an example, consider the following form structure and route: ```rust # #[macro_use] extern crate rocket; # fn main() {} 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 # #[macro_use] extern crate rocket; # use rocket::form::Form; # #[derive(FromForm, UriDisplayQuery)] # struct UserDetails<'r> { # age: Option, # nickname: &'r str, # } # #[post("/user/?")] # fn add_user(id: usize, details: UserDetails) { /* .. */ } let link = uri!(add_user(120, UserDetails { age: Some(20), nickname: "Bob".into() })); assert_eq!(link.to_string(), "/user/120?age=20&nickname=Bob"); ``` ### Typed URI Parts The [`Part`] trait categorizes types that mark a part of the URI as either a [`Path`] or a [`Query`]. Said another way, types that implement `Part` are marker types that represent a part of a URI at the type-level. Traits such as [`UriDisplay`] and [`FromUriParam`] bound a generic parameter by `Part`: `P: Part`. This creates two instances of each trait: `UriDisplay` and `UriDisplay`, and `FromUriParam` and `FromUriParam`. As the names might imply, the `Path` version of the traits is used when displaying parameters in the path part of the URI while the `Query` version is used when displaying parameters in the query part of the URI. These distinct versions of the traits exist exactly to differentiate, at the type-level, where in the URI a value is to be written to, allowing for type safety in the face of differences between the two locations. For example, while it is valid to use a value of `None` in the query part, omitting the parameter entirely, doing so is _not_ valid in the path part. By differentiating in the type system, both of these conditions can be enforced appropriately through distinct implementations of `FromUriParam` and `FromUriParam`. This division has an effect on how the `uri!` macro can be invoked. In query parts, for a route type of `Option`, you _must_ supply a type of `Option`, `Result`, or an ignored `_` to the `uri!` invocation. By contrast, you _cannot_ supply such a type in the path part. This ensures that a valid URI is _always_ generated. ```rust # #[macro_use] extern crate rocket; #[get("//?")] fn person(id: Option, name: &str, age: Option) { /* .. */ } // Note that `id` is `Option` in the route, but `id` in `uri!` _cannot_ // be an `Option`. `age`, on the other hand, _must_ be an `Option` (or `Result` // or `_`) as its in the query part and is allowed to be ignored. let mike = uri!(person(id = 101, name = "Mike", age = Some(28))); assert_eq!(mike.to_string(), "/101/Mike?age=28"); ``` ### Conversions [`FromUriParam`] is used to perform a conversion for each value passed to `uri!` before it is displayed with `UriDisplay`. If a `T: FromUriParam` implementation exists for a type `T` for part URI part `P`, then a value of type `S` can be used in `uri!` macro for a route URI parameter declared with a type of `T` in part `P`. For example, the following implementation, provided by Rocket, allows an `&str` to be used in a `uri!` invocation for route URI parameters declared as `String`: ```rust # use rocket::http::uri::fmt::{FromUriParam, Part}; # struct S; # type String = S; impl<'a, P: Part> FromUriParam for String { type Target = &'a str; # fn from_uri_param(s: &'a str) -> Self::Target { "hi" } } ``` Other conversions to be aware of are: * `&T` to `T` * `&mut T` to `T` * `String` to `&str` * `&str` to `&Path` * `&str` to `PathBuf` * `T` to `Form` The following conversions only apply to path parts: * `T` to `Option` * `T` to `Result` The following conversions are implemented only in query parts: * `Option` to `Result` (for any `E`) * `Result` to `Option` (for any `E`) Conversions are transitive. That is, a conversion from `A -> B` and a conversion `B -> C` implies a conversion from `A -> C`. For instance, a value of type `&str` can be supplied when a value of type `Option` is expected: ```rust # #[macro_use] extern crate rocket; use std::path::PathBuf; #[get("/person//")] fn person(id: usize, details: Option) { /* .. */ } uri!(person(id = 100, details = "a/b/c")); ``` See the [`FromUriParam`] documentation for further details. [`Origin`]: @api/master/rocket/http/uri/struct.Origin.html [`Part`]: @api/master/rocket/http/uri/fmt/trait.Part.html [`Uri`]: @api/master/rocket/http/uri/enum.Uri.html [`Redirect::to()`]: @api/master/rocket/response/struct.Redirect.html#method.to [`uri!`]: @api/master/rocket/macro.uri.html [`UriDisplay`]: @api/master/rocket/http/uri/fmt/trait.UriDisplay.html [`FromUriParam`]: @api/master/rocket/http/uri/fmt/trait.FromUriParam.html [`Path`]: @api/master/rocket/http/uri/fmt/enum.Path.html [`Query`]: @api/master/rocket/http/uri/fmt/enum.Query.html [`Ignorable`]: @api/master/rocket/http/uri/fmt/trait.Ignorable.html [`UriDisplayPath`]: @api/master/rocket/derive.UriDisplayPath.html [`UriDisplayQuery`]: @api/master/rocket/derive.UriDisplayQuery.html