Rocket/docs/guide/06-responses.md

847 lines
28 KiB
Markdown
Raw Normal View History

+++
summary = "generating responses and using typed URIs"
+++
# Responses
You may have noticed that the return type of a handler appears to be arbitrary,
2017-07-04 09:37:21 +00:00
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
2017-07-04 09:37:21 +00:00
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
Responders compose by _wrapping_ (encapsulating) other responders. Naturally, we
call these _wrapping_ responders. A wrapping responder takes a response from an
existing responder `R`, modifies it, and then returns it. They typically have
the following shape:
```rust
struct WrappingResponder<R>(R);
```
Examples include `Responder`s in the [`status` module], which override the
status code of the wrapped `Responder`'s response, and `Responder`s in the
[`content` module], which override the Content-Type.
As a concrete example, the [`Accepted`] wrapping responder sets the status to
2018-10-16 05:50:35 +00:00
`202 - Accepted`. It can be used as follows:
```rust
# #[macro_use] extern crate rocket;
# fn main() {}
2017-07-04 09:37:21 +00:00
use rocket::response::status;
#[post("/<id>")]
fn new(id: usize) -> status::Accepted<String> {
// Modifies the response generated by `String` to have a status of `202`.
status::Accepted(format!("id: '{}'", id))
}
```
Because wrapping responders are themselves responders, they too can be wrapped.
This is what allows responders to compose, enabling powerful combinations of
simple primitives to form more powerful abstractions. For example, combining the
[`content::RawJson`] and [`status::Custom`] responders allows creating a
response with a Content-Type of JSON and an arbitrary status code like `418 I'm
a teapot` from an `&'static str`:
```rust
# #[macro_use] extern crate rocket;
use rocket::http::Status;
use rocket::response::{content, status};
#[get("/")]
fn json() -> status::Custom<content::RawJson<&'static str>> {
status::Custom(Status::ImATeapot, content::RawJson("{ \"hi\": \"world\" }"))
}
```
! warning: This is _not_ the same as [`serde::json::Json`]!
! note: There are simpler alternatives for setting a status and content-types.
The built-in `(Status, R)` and `(ContentType, R)` wrapping responders
also override the `Status` and `Content-Type` of responses, respectively, and
may be simpler alternatives:
2017-07-04 09:37:21 +00:00
```rust
# #[macro_use] extern crate rocket;
use rocket::http::{Status, ContentType};
#[get("/")]
fn json() -> (Status, (ContentType, &'static str)) {
(Status::ImATeapot, (ContentType::JSON, "{ \"hi\": \"world\" }"))
}
```
Composition through wrapping is useful when you want to change one or two
properties of an existing response. For more complex use-cases, instead consider
deriving 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::RawJson`]: @api/master/rocket/response/content/struct.RawJson.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
[`status` module]: @api/master/rocket/response/status/
[`content` module]: @api/master/rocket/response/content/
2017-07-04 09:37:21 +00:00
### 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
2017-07-04 09:37:21 +00:00
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<String>),
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
2017-07-10 11:59:55 +00:00
## Implementations
2017-07-04 09:37:21 +00:00
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.
2017-07-10 11:59:55 +00:00
### Strings
2017-07-04 09:37:21 +00:00
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);
2020-07-11 16:41:53 +00:00
#[rocket::async_trait]
impl<'r> Responder<'r, 'static> for String {
fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
2017-07-04 09:37:21 +00:00
Response::build()
.header(ContentType::Plain)
# /*
2020-07-11 16:41:53 +00:00
.sized_body(self.len(), Cursor::new(self))
# */
2020-07-11 16:41:53 +00:00
# .sized_body(self.0.len(), Cursor::new(self.0))
2017-07-04 09:37:21 +00:00
.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() {}
2017-07-04 09:37:21 +00:00
#[get("/string")]
fn handler() -> &'static str {
"Hello there! I'm a string!"
}
```
2017-07-10 11:59:55 +00:00
### `Option`
2017-07-04 09:37:21 +00:00
2018-08-09 02:06:52 +00:00
`Option` is a _wrapping_ responder: an `Option<T>` can only be returned when `T`
2017-07-04 09:37:21 +00:00
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
2017-07-04 09:37:21 +00:00
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;
2017-07-04 09:37:21 +00:00
#[get("/<file..>")]
2020-07-11 16:41:53 +00:00
async fn files(file: PathBuf) -> Option<NamedFile> {
NamedFile::open(Path::new("static/").join(file)).await.ok()
2017-07-04 09:37:21 +00:00
}
```
2017-07-10 11:59:55 +00:00
### `Result`
2017-07-04 09:37:21 +00:00
`Result` is another _wrapping_ responder: a `Result<T, E>` can only be returned
when `T` implements `Responder` and `E` implements `Responder`.
2017-07-04 09:37:21 +00:00
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:
2017-07-04 09:37:21 +00:00
```rust
# #[macro_use] extern crate rocket;
# fn main() {}
# use std::path::{Path, PathBuf};
use rocket::fs::NamedFile;
2017-07-04 09:37:21 +00:00
use rocket::response::status::NotFound;
#[get("/<file..>")]
2020-07-11 16:41:53 +00:00
async fn files(file: PathBuf) -> Result<NamedFile, NotFound<String>> {
2017-07-04 09:37:21 +00:00
let path = Path::new("static/").join(file);
2020-07-11 16:41:53 +00:00
NamedFile::open(&path).await.map_err(|e| NotFound(e.to_string()))
2017-07-04 09:37:21 +00:00
}
```
## Rocket Responders
Some of Rocket's best features are implemented through responders. Among these
are:
2017-07-04 09:37:21 +00:00
* [`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.
2023-03-23 21:44:16 +00:00
* [`content`] - Contains types that override the Content-Type of a response.
2017-07-04 09:37:21 +00:00
* [`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, Tera or MiniJinja.
2017-07-04 09:37:21 +00:00
[`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
2017-07-04 09:37:21 +00:00
### Async Streams
2017-07-04 09:37:21 +00:00
2021-06-09 09:53:11 +00:00
The [`stream`] responders allow serving potentially infinite [async `Stream`]s.
A stream can be created from any async `Stream` or `AsyncRead` type, or via
2021-06-09 09:53:11 +00:00
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).
2017-07-04 09:37:21 +00:00
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;
2020-07-11 16:41:53 +00:00
use std::net::SocketAddr;
use rocket::tokio::net::TcpStream;
use rocket::response::stream::ReaderStream;
2020-07-11 16:41:53 +00:00
2017-07-04 09:37:21 +00:00
#[get("/stream")]
async fn stream() -> io::Result<ReaderStream![TcpStream]> {
2020-07-11 16:41:53 +00:00
let addr = SocketAddr::from(([127, 0, 0, 1], 9999));
let stream = TcpStream::connect(addr).await?;
Ok(ReaderStream::one(stream))
2017-07-04 09:37:21 +00:00
}
```
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
2021-06-09 09:53:11 +00:00
[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
2017-07-04 09:37:21 +00:00
2023-11-22 20:38:53 +00:00
### 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/
2023-11-22 20:38:53 +00:00
2017-07-04 09:37:21 +00:00
### JSON
The [`Json`] responder in allows you to easily respond with well-formed JSON
data: simply return a value of type `Json<T>` 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.
2017-07-04 09:37:21 +00:00
As an example, to respond with the JSON value of a `Task` structure, we might
2017-07-04 09:37:21 +00:00
write:
```rust
# #[macro_use] extern crate rocket;
use rocket::serde::{Serialize, json::Json};
2017-07-04 09:37:21 +00:00
#[derive(Serialize)]
#[serde(crate = "rocket::serde")]
struct Task { /* .. */ }
#[get("/todo")]
fn todo() -> Json<Task> {
Json(Task { /* .. */ })
}
```
! note: You must enable Rocket's `json` crate feature to use the [`Json`] type.
2018-10-16 06:24:23 +00:00
The `Json` type serializes the structure into JSON, sets the Content-Type to
2017-07-04 09:37:21 +00:00
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
2017-07-04 09:37:21 +00:00
[`Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html
[`serde`]: https://serde.rs
[serialization example]: @git/master/examples/serialization
## Templates
2017-07-04 09:37:21 +00:00
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 {
# /*
2017-07-04 09:37:21 +00:00
let context = /* object-like value */;
# */ let context = ();
2017-07-04 09:37:21 +00:00
Template::render("index", &context)
2017-06-06 17:23:46 +00:00
}
```
Templates are rendered with the `render` method. The method takes in the name of
2017-07-04 09:37:21 +00:00
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
2018-10-27 03:52:06 +00:00
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())
}
```
2018-10-27 03:52:06 +00:00
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`.
2018-10-27 03:52:06 +00:00
[`context!`]: @api/master/rocket_dyn_templates/macro.context.html
### Live Reloading
2018-10-27 03:52:06 +00:00
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 Tera, Handlebars and MiniJinja
templating to implement the same application.
2017-07-04 09:37:21 +00:00
[configurable]: ../configuration/
## Typed URIs
2018-10-27 03:52:06 +00:00
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.
2018-10-27 03:52:06 +00:00
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<Uri>` (and by extension, `TryInto<Uri>`), 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("/<id>/<name>?<age>")]
2021-03-27 23:25:39 +00:00
fn person(id: Option<usize>, name: &str, age: Option<u8>) { /* .. */ }
```
URIs to `person` can be created as follows:
```rust
# #[macro_use] extern crate rocket;
# #[get("/<id>/<name>?<age>")]
2021-03-27 23:25:39 +00:00
# fn person(id: Option<usize>, name: &str, age: Option<u8>) { /* .. */ }
// 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"));
| ^^^^^^^^^^^^
|
2021-03-27 23:25:39 +00:00
= note: expected parameters: id: Option <usize>, name: &str, age: Option <u8>
```
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<Path, &str>` 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() {}
UTF-8 routes. Forms revamp. Temp files. Capped. So. Many. Changes. This is an insane commit: simultaneously one of the best (because of all the wonderful improvements!) and one of the worst (because it is just massive) in the project's history. Routing: * All UTF-8 characters are accepted everywhere in route paths. (#998) * `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]` becomes `#[route(GET, uri = "..")]`. Forms Revamp * All form related types now reside in a new `form` module. * Multipart forms are supported. (resolves #106) * Collections are supported in forms and queries. (resolves #205) * Nested structures in forms and queries are supported. (resolves #313) * Form fields can be ad-hoc validated with `#[field(validate = expr)]`. * `FromFormValue` is now `FromFormField`, blanket implements `FromForm`. * Form field values are always percent-decoded apriori. Temporary Files * A new `TempFile` data and form guard allows streaming data directly to a file which can then be persisted. * A new `temp_dir` config parameter specifies where to store `TempFile`. * The limits `file` and `file/$ext`, where `$ext` is the file extension, determines the data limit for a `TempFile`. Capped * A new `Capped` type is used to indicate when data has been truncated due to incoming data limits. It allows checking whether data is complete or truncated. * `DataStream` methods return `Capped` types. * `DataStream` API has been revamped to account for `Capped` types. * Several `Capped<T>` types implement `FromData`, `FromForm`. * HTTP 413 (Payload Too Large) errors are now returned when data limits are exceeded. (resolves #972) Hierarchical Limits * Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c` falls back to `a/b` then `a`. Core * `&RawStr` no longer implements `FromParam`. * `&str` implements `FromParam`, `FromData`, `FromForm`. * `FromTransformedData` was removed. * `FromData` gained a lifetime for use with request-local data. * The default error HTML is more compact. * `&Config` is a request guard. * The `DataStream` interface was entirely revamped. * `State` is only exported via `rocket::State`. * A `request::local_cache!()` macro was added for storing values in request-local cache without consideration for type uniqueness by using a locally generated anonymous type. * `Request::get_param()` is now `Request::param()`. * `Request::get_segments()` is now `Request::segments()`, takes a range. * `Request::get_query_value()` is now `Request::query_value()`, can parse any `FromForm` including sequences. * `std::io::Error` implements `Responder` like `Debug<std::io::Error>`. * `(Status, R)` where `R: Responder` implements `Responder` by overriding the `Status` of `R`. * The name of a route is printed first during route matching. * `FlashMessage` now only has one lifetime generic. HTTP * `RawStr` implements `serde::{Serialize, Deserialize}`. * `RawStr` implements _many_ more methods, in particular, those related to the `Pattern` API. * `RawStr::from_str()` is now `RawStr::new()`. * `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as necessary, return `Cow`. * `Status` implements `Default` with `Status::Ok`. * `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`. * Authority and origin part of `Absolute` can be modified with new `Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods. * `Origin::segments()` was removed in favor of methods split into query and path parts and into raw and decoded versions. * The `Segments` iterator is smarter, returns decoded `&str` items. * `Segments::into_path_buf()` is now `Segments::to_path_buf()`. * A new `QuerySegments` is the analogous query segment iterator. * Once set, `expires` on private cookies is not overwritten. (resolves #1506) * `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`. Codegen * Preserve more spans in `uri!` macro. * Preserve spans `FromForm` field types. * All dynamic parameters in a query string must typecheck as `FromForm`. * `FromFormValue` derive removed; `FromFormField` added. * The `form` `FromForm` and `FromFormField` field attribute is now named `field`. `#[form(field = ..)]` is now `#[field(name = ..)]`. Contrib * `Json` implements `FromForm`. * `MsgPack` implements `FromForm`. * The `json!` macro is exported as `rocket_contrib::json::json!`. * Added clarifying docs to `StaticFiles`. Examples * `form_validation` and `form_kitchen_sink` removed in favor of `forms`. * The `hello_world` example uses unicode in paths. * The `json` example only allocates as necessary. Internal * Codegen uses new `exports` module with the following conventions: - Locals starts with `__` and are lowercased. - Rocket modules start with `_` and are lowercased. - `std` types start with `_` and are titlecased. - Rocket types are titlecased. * A `header` module was added to `http`, contains header types. * `SAFETY` is used as doc-string keyword for `unsafe` related comments. * The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
use rocket::form::Form;
#[derive(FromForm, UriDisplayQuery)]
struct UserDetails<'r> {
age: Option<usize>,
UTF-8 routes. Forms revamp. Temp files. Capped. So. Many. Changes. This is an insane commit: simultaneously one of the best (because of all the wonderful improvements!) and one of the worst (because it is just massive) in the project's history. Routing: * All UTF-8 characters are accepted everywhere in route paths. (#998) * `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]` becomes `#[route(GET, uri = "..")]`. Forms Revamp * All form related types now reside in a new `form` module. * Multipart forms are supported. (resolves #106) * Collections are supported in forms and queries. (resolves #205) * Nested structures in forms and queries are supported. (resolves #313) * Form fields can be ad-hoc validated with `#[field(validate = expr)]`. * `FromFormValue` is now `FromFormField`, blanket implements `FromForm`. * Form field values are always percent-decoded apriori. Temporary Files * A new `TempFile` data and form guard allows streaming data directly to a file which can then be persisted. * A new `temp_dir` config parameter specifies where to store `TempFile`. * The limits `file` and `file/$ext`, where `$ext` is the file extension, determines the data limit for a `TempFile`. Capped * A new `Capped` type is used to indicate when data has been truncated due to incoming data limits. It allows checking whether data is complete or truncated. * `DataStream` methods return `Capped` types. * `DataStream` API has been revamped to account for `Capped` types. * Several `Capped<T>` types implement `FromData`, `FromForm`. * HTTP 413 (Payload Too Large) errors are now returned when data limits are exceeded. (resolves #972) Hierarchical Limits * Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c` falls back to `a/b` then `a`. Core * `&RawStr` no longer implements `FromParam`. * `&str` implements `FromParam`, `FromData`, `FromForm`. * `FromTransformedData` was removed. * `FromData` gained a lifetime for use with request-local data. * The default error HTML is more compact. * `&Config` is a request guard. * The `DataStream` interface was entirely revamped. * `State` is only exported via `rocket::State`. * A `request::local_cache!()` macro was added for storing values in request-local cache without consideration for type uniqueness by using a locally generated anonymous type. * `Request::get_param()` is now `Request::param()`. * `Request::get_segments()` is now `Request::segments()`, takes a range. * `Request::get_query_value()` is now `Request::query_value()`, can parse any `FromForm` including sequences. * `std::io::Error` implements `Responder` like `Debug<std::io::Error>`. * `(Status, R)` where `R: Responder` implements `Responder` by overriding the `Status` of `R`. * The name of a route is printed first during route matching. * `FlashMessage` now only has one lifetime generic. HTTP * `RawStr` implements `serde::{Serialize, Deserialize}`. * `RawStr` implements _many_ more methods, in particular, those related to the `Pattern` API. * `RawStr::from_str()` is now `RawStr::new()`. * `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as necessary, return `Cow`. * `Status` implements `Default` with `Status::Ok`. * `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`. * Authority and origin part of `Absolute` can be modified with new `Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods. * `Origin::segments()` was removed in favor of methods split into query and path parts and into raw and decoded versions. * The `Segments` iterator is smarter, returns decoded `&str` items. * `Segments::into_path_buf()` is now `Segments::to_path_buf()`. * A new `QuerySegments` is the analogous query segment iterator. * Once set, `expires` on private cookies is not overwritten. (resolves #1506) * `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`. Codegen * Preserve more spans in `uri!` macro. * Preserve spans `FromForm` field types. * All dynamic parameters in a query string must typecheck as `FromForm`. * `FromFormValue` derive removed; `FromFormField` added. * The `form` `FromForm` and `FromFormField` field attribute is now named `field`. `#[form(field = ..)]` is now `#[field(name = ..)]`. Contrib * `Json` implements `FromForm`. * `MsgPack` implements `FromForm`. * The `json!` macro is exported as `rocket_contrib::json::json!`. * Added clarifying docs to `StaticFiles`. Examples * `form_validation` and `form_kitchen_sink` removed in favor of `forms`. * The `hello_world` example uses unicode in paths. * The `json` example only allocates as necessary. Internal * Codegen uses new `exports` module with the following conventions: - Locals starts with `__` and are lowercased. - Rocket modules start with `_` and are lowercased. - `std` types start with `_` and are titlecased. - Rocket types are titlecased. * A `header` module was added to `http`, contains header types. * `SAFETY` is used as doc-string keyword for `unsafe` related comments. * The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
nickname: &'r str,
}
#[post("/user/<id>?<details..>")]
UTF-8 routes. Forms revamp. Temp files. Capped. So. Many. Changes. This is an insane commit: simultaneously one of the best (because of all the wonderful improvements!) and one of the worst (because it is just massive) in the project's history. Routing: * All UTF-8 characters are accepted everywhere in route paths. (#998) * `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]` becomes `#[route(GET, uri = "..")]`. Forms Revamp * All form related types now reside in a new `form` module. * Multipart forms are supported. (resolves #106) * Collections are supported in forms and queries. (resolves #205) * Nested structures in forms and queries are supported. (resolves #313) * Form fields can be ad-hoc validated with `#[field(validate = expr)]`. * `FromFormValue` is now `FromFormField`, blanket implements `FromForm`. * Form field values are always percent-decoded apriori. Temporary Files * A new `TempFile` data and form guard allows streaming data directly to a file which can then be persisted. * A new `temp_dir` config parameter specifies where to store `TempFile`. * The limits `file` and `file/$ext`, where `$ext` is the file extension, determines the data limit for a `TempFile`. Capped * A new `Capped` type is used to indicate when data has been truncated due to incoming data limits. It allows checking whether data is complete or truncated. * `DataStream` methods return `Capped` types. * `DataStream` API has been revamped to account for `Capped` types. * Several `Capped<T>` types implement `FromData`, `FromForm`. * HTTP 413 (Payload Too Large) errors are now returned when data limits are exceeded. (resolves #972) Hierarchical Limits * Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c` falls back to `a/b` then `a`. Core * `&RawStr` no longer implements `FromParam`. * `&str` implements `FromParam`, `FromData`, `FromForm`. * `FromTransformedData` was removed. * `FromData` gained a lifetime for use with request-local data. * The default error HTML is more compact. * `&Config` is a request guard. * The `DataStream` interface was entirely revamped. * `State` is only exported via `rocket::State`. * A `request::local_cache!()` macro was added for storing values in request-local cache without consideration for type uniqueness by using a locally generated anonymous type. * `Request::get_param()` is now `Request::param()`. * `Request::get_segments()` is now `Request::segments()`, takes a range. * `Request::get_query_value()` is now `Request::query_value()`, can parse any `FromForm` including sequences. * `std::io::Error` implements `Responder` like `Debug<std::io::Error>`. * `(Status, R)` where `R: Responder` implements `Responder` by overriding the `Status` of `R`. * The name of a route is printed first during route matching. * `FlashMessage` now only has one lifetime generic. HTTP * `RawStr` implements `serde::{Serialize, Deserialize}`. * `RawStr` implements _many_ more methods, in particular, those related to the `Pattern` API. * `RawStr::from_str()` is now `RawStr::new()`. * `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as necessary, return `Cow`. * `Status` implements `Default` with `Status::Ok`. * `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`. * Authority and origin part of `Absolute` can be modified with new `Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods. * `Origin::segments()` was removed in favor of methods split into query and path parts and into raw and decoded versions. * The `Segments` iterator is smarter, returns decoded `&str` items. * `Segments::into_path_buf()` is now `Segments::to_path_buf()`. * A new `QuerySegments` is the analogous query segment iterator. * Once set, `expires` on private cookies is not overwritten. (resolves #1506) * `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`. Codegen * Preserve more spans in `uri!` macro. * Preserve spans `FromForm` field types. * All dynamic parameters in a query string must typecheck as `FromForm`. * `FromFormValue` derive removed; `FromFormField` added. * The `form` `FromForm` and `FromFormField` field attribute is now named `field`. `#[form(field = ..)]` is now `#[field(name = ..)]`. Contrib * `Json` implements `FromForm`. * `MsgPack` implements `FromForm`. * The `json!` macro is exported as `rocket_contrib::json::json!`. * Added clarifying docs to `StaticFiles`. Examples * `form_validation` and `form_kitchen_sink` removed in favor of `forms`. * The `hello_world` example uses unicode in paths. * The `json` example only allocates as necessary. Internal * Codegen uses new `exports` module with the following conventions: - Locals starts with `__` and are lowercased. - Rocket modules start with `_` and are lowercased. - `std` types start with `_` and are titlecased. - Rocket types are titlecased. * A `header` module was added to `http`, contains header types. * `SAFETY` is used as doc-string keyword for `unsafe` related comments. * The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
fn add_user(id: usize, details: UserDetails) { /* .. */ }
```
By deriving using `UriDisplayQuery`, an implementation of `UriDisplay<Query>` is
automatically generated, allowing for URIs to `add_user` to be generated using
`uri!`:
```rust
# #[macro_use] extern crate rocket;
UTF-8 routes. Forms revamp. Temp files. Capped. So. Many. Changes. This is an insane commit: simultaneously one of the best (because of all the wonderful improvements!) and one of the worst (because it is just massive) in the project's history. Routing: * All UTF-8 characters are accepted everywhere in route paths. (#998) * `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]` becomes `#[route(GET, uri = "..")]`. Forms Revamp * All form related types now reside in a new `form` module. * Multipart forms are supported. (resolves #106) * Collections are supported in forms and queries. (resolves #205) * Nested structures in forms and queries are supported. (resolves #313) * Form fields can be ad-hoc validated with `#[field(validate = expr)]`. * `FromFormValue` is now `FromFormField`, blanket implements `FromForm`. * Form field values are always percent-decoded apriori. Temporary Files * A new `TempFile` data and form guard allows streaming data directly to a file which can then be persisted. * A new `temp_dir` config parameter specifies where to store `TempFile`. * The limits `file` and `file/$ext`, where `$ext` is the file extension, determines the data limit for a `TempFile`. Capped * A new `Capped` type is used to indicate when data has been truncated due to incoming data limits. It allows checking whether data is complete or truncated. * `DataStream` methods return `Capped` types. * `DataStream` API has been revamped to account for `Capped` types. * Several `Capped<T>` types implement `FromData`, `FromForm`. * HTTP 413 (Payload Too Large) errors are now returned when data limits are exceeded. (resolves #972) Hierarchical Limits * Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c` falls back to `a/b` then `a`. Core * `&RawStr` no longer implements `FromParam`. * `&str` implements `FromParam`, `FromData`, `FromForm`. * `FromTransformedData` was removed. * `FromData` gained a lifetime for use with request-local data. * The default error HTML is more compact. * `&Config` is a request guard. * The `DataStream` interface was entirely revamped. * `State` is only exported via `rocket::State`. * A `request::local_cache!()` macro was added for storing values in request-local cache without consideration for type uniqueness by using a locally generated anonymous type. * `Request::get_param()` is now `Request::param()`. * `Request::get_segments()` is now `Request::segments()`, takes a range. * `Request::get_query_value()` is now `Request::query_value()`, can parse any `FromForm` including sequences. * `std::io::Error` implements `Responder` like `Debug<std::io::Error>`. * `(Status, R)` where `R: Responder` implements `Responder` by overriding the `Status` of `R`. * The name of a route is printed first during route matching. * `FlashMessage` now only has one lifetime generic. HTTP * `RawStr` implements `serde::{Serialize, Deserialize}`. * `RawStr` implements _many_ more methods, in particular, those related to the `Pattern` API. * `RawStr::from_str()` is now `RawStr::new()`. * `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as necessary, return `Cow`. * `Status` implements `Default` with `Status::Ok`. * `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`. * Authority and origin part of `Absolute` can be modified with new `Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods. * `Origin::segments()` was removed in favor of methods split into query and path parts and into raw and decoded versions. * The `Segments` iterator is smarter, returns decoded `&str` items. * `Segments::into_path_buf()` is now `Segments::to_path_buf()`. * A new `QuerySegments` is the analogous query segment iterator. * Once set, `expires` on private cookies is not overwritten. (resolves #1506) * `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`. Codegen * Preserve more spans in `uri!` macro. * Preserve spans `FromForm` field types. * All dynamic parameters in a query string must typecheck as `FromForm`. * `FromFormValue` derive removed; `FromFormField` added. * The `form` `FromForm` and `FromFormField` field attribute is now named `field`. `#[form(field = ..)]` is now `#[field(name = ..)]`. Contrib * `Json` implements `FromForm`. * `MsgPack` implements `FromForm`. * The `json!` macro is exported as `rocket_contrib::json::json!`. * Added clarifying docs to `StaticFiles`. Examples * `form_validation` and `form_kitchen_sink` removed in favor of `forms`. * The `hello_world` example uses unicode in paths. * The `json` example only allocates as necessary. Internal * Codegen uses new `exports` module with the following conventions: - Locals starts with `__` and are lowercased. - Rocket modules start with `_` and are lowercased. - `std` types start with `_` and are titlecased. - Rocket types are titlecased. * A `header` module was added to `http`, contains header types. * `SAFETY` is used as doc-string keyword for `unsafe` related comments. * The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
# use rocket::form::Form;
# #[derive(FromForm, UriDisplayQuery)]
# struct UserDetails<'r> {
# age: Option<usize>,
UTF-8 routes. Forms revamp. Temp files. Capped. So. Many. Changes. This is an insane commit: simultaneously one of the best (because of all the wonderful improvements!) and one of the worst (because it is just massive) in the project's history. Routing: * All UTF-8 characters are accepted everywhere in route paths. (#998) * `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]` becomes `#[route(GET, uri = "..")]`. Forms Revamp * All form related types now reside in a new `form` module. * Multipart forms are supported. (resolves #106) * Collections are supported in forms and queries. (resolves #205) * Nested structures in forms and queries are supported. (resolves #313) * Form fields can be ad-hoc validated with `#[field(validate = expr)]`. * `FromFormValue` is now `FromFormField`, blanket implements `FromForm`. * Form field values are always percent-decoded apriori. Temporary Files * A new `TempFile` data and form guard allows streaming data directly to a file which can then be persisted. * A new `temp_dir` config parameter specifies where to store `TempFile`. * The limits `file` and `file/$ext`, where `$ext` is the file extension, determines the data limit for a `TempFile`. Capped * A new `Capped` type is used to indicate when data has been truncated due to incoming data limits. It allows checking whether data is complete or truncated. * `DataStream` methods return `Capped` types. * `DataStream` API has been revamped to account for `Capped` types. * Several `Capped<T>` types implement `FromData`, `FromForm`. * HTTP 413 (Payload Too Large) errors are now returned when data limits are exceeded. (resolves #972) Hierarchical Limits * Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c` falls back to `a/b` then `a`. Core * `&RawStr` no longer implements `FromParam`. * `&str` implements `FromParam`, `FromData`, `FromForm`. * `FromTransformedData` was removed. * `FromData` gained a lifetime for use with request-local data. * The default error HTML is more compact. * `&Config` is a request guard. * The `DataStream` interface was entirely revamped. * `State` is only exported via `rocket::State`. * A `request::local_cache!()` macro was added for storing values in request-local cache without consideration for type uniqueness by using a locally generated anonymous type. * `Request::get_param()` is now `Request::param()`. * `Request::get_segments()` is now `Request::segments()`, takes a range. * `Request::get_query_value()` is now `Request::query_value()`, can parse any `FromForm` including sequences. * `std::io::Error` implements `Responder` like `Debug<std::io::Error>`. * `(Status, R)` where `R: Responder` implements `Responder` by overriding the `Status` of `R`. * The name of a route is printed first during route matching. * `FlashMessage` now only has one lifetime generic. HTTP * `RawStr` implements `serde::{Serialize, Deserialize}`. * `RawStr` implements _many_ more methods, in particular, those related to the `Pattern` API. * `RawStr::from_str()` is now `RawStr::new()`. * `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as necessary, return `Cow`. * `Status` implements `Default` with `Status::Ok`. * `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`. * Authority and origin part of `Absolute` can be modified with new `Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods. * `Origin::segments()` was removed in favor of methods split into query and path parts and into raw and decoded versions. * The `Segments` iterator is smarter, returns decoded `&str` items. * `Segments::into_path_buf()` is now `Segments::to_path_buf()`. * A new `QuerySegments` is the analogous query segment iterator. * Once set, `expires` on private cookies is not overwritten. (resolves #1506) * `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`. Codegen * Preserve more spans in `uri!` macro. * Preserve spans `FromForm` field types. * All dynamic parameters in a query string must typecheck as `FromForm`. * `FromFormValue` derive removed; `FromFormField` added. * The `form` `FromForm` and `FromFormField` field attribute is now named `field`. `#[form(field = ..)]` is now `#[field(name = ..)]`. Contrib * `Json` implements `FromForm`. * `MsgPack` implements `FromForm`. * The `json!` macro is exported as `rocket_contrib::json::json!`. * Added clarifying docs to `StaticFiles`. Examples * `form_validation` and `form_kitchen_sink` removed in favor of `forms`. * The `hello_world` example uses unicode in paths. * The `json` example only allocates as necessary. Internal * Codegen uses new `exports` module with the following conventions: - Locals starts with `__` and are lowercased. - Rocket modules start with `_` and are lowercased. - `std` types start with `_` and are titlecased. - Rocket types are titlecased. * A `header` module was added to `http`, contains header types. * `SAFETY` is used as doc-string keyword for `unsafe` related comments. * The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
# nickname: &'r str,
# }
# #[post("/user/<id>?<details..>")]
UTF-8 routes. Forms revamp. Temp files. Capped. So. Many. Changes. This is an insane commit: simultaneously one of the best (because of all the wonderful improvements!) and one of the worst (because it is just massive) in the project's history. Routing: * All UTF-8 characters are accepted everywhere in route paths. (#998) * `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]` becomes `#[route(GET, uri = "..")]`. Forms Revamp * All form related types now reside in a new `form` module. * Multipart forms are supported. (resolves #106) * Collections are supported in forms and queries. (resolves #205) * Nested structures in forms and queries are supported. (resolves #313) * Form fields can be ad-hoc validated with `#[field(validate = expr)]`. * `FromFormValue` is now `FromFormField`, blanket implements `FromForm`. * Form field values are always percent-decoded apriori. Temporary Files * A new `TempFile` data and form guard allows streaming data directly to a file which can then be persisted. * A new `temp_dir` config parameter specifies where to store `TempFile`. * The limits `file` and `file/$ext`, where `$ext` is the file extension, determines the data limit for a `TempFile`. Capped * A new `Capped` type is used to indicate when data has been truncated due to incoming data limits. It allows checking whether data is complete or truncated. * `DataStream` methods return `Capped` types. * `DataStream` API has been revamped to account for `Capped` types. * Several `Capped<T>` types implement `FromData`, `FromForm`. * HTTP 413 (Payload Too Large) errors are now returned when data limits are exceeded. (resolves #972) Hierarchical Limits * Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c` falls back to `a/b` then `a`. Core * `&RawStr` no longer implements `FromParam`. * `&str` implements `FromParam`, `FromData`, `FromForm`. * `FromTransformedData` was removed. * `FromData` gained a lifetime for use with request-local data. * The default error HTML is more compact. * `&Config` is a request guard. * The `DataStream` interface was entirely revamped. * `State` is only exported via `rocket::State`. * A `request::local_cache!()` macro was added for storing values in request-local cache without consideration for type uniqueness by using a locally generated anonymous type. * `Request::get_param()` is now `Request::param()`. * `Request::get_segments()` is now `Request::segments()`, takes a range. * `Request::get_query_value()` is now `Request::query_value()`, can parse any `FromForm` including sequences. * `std::io::Error` implements `Responder` like `Debug<std::io::Error>`. * `(Status, R)` where `R: Responder` implements `Responder` by overriding the `Status` of `R`. * The name of a route is printed first during route matching. * `FlashMessage` now only has one lifetime generic. HTTP * `RawStr` implements `serde::{Serialize, Deserialize}`. * `RawStr` implements _many_ more methods, in particular, those related to the `Pattern` API. * `RawStr::from_str()` is now `RawStr::new()`. * `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as necessary, return `Cow`. * `Status` implements `Default` with `Status::Ok`. * `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`. * Authority and origin part of `Absolute` can be modified with new `Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods. * `Origin::segments()` was removed in favor of methods split into query and path parts and into raw and decoded versions. * The `Segments` iterator is smarter, returns decoded `&str` items. * `Segments::into_path_buf()` is now `Segments::to_path_buf()`. * A new `QuerySegments` is the analogous query segment iterator. * Once set, `expires` on private cookies is not overwritten. (resolves #1506) * `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`. Codegen * Preserve more spans in `uri!` macro. * Preserve spans `FromForm` field types. * All dynamic parameters in a query string must typecheck as `FromForm`. * `FromFormValue` derive removed; `FromFormField` added. * The `form` `FromForm` and `FromFormField` field attribute is now named `field`. `#[form(field = ..)]` is now `#[field(name = ..)]`. Contrib * `Json` implements `FromForm`. * `MsgPack` implements `FromForm`. * The `json!` macro is exported as `rocket_contrib::json::json!`. * Added clarifying docs to `StaticFiles`. Examples * `form_validation` and `form_kitchen_sink` removed in favor of `forms`. * The `hello_world` example uses unicode in paths. * The `json` example only allocates as necessary. Internal * Codegen uses new `exports` module with the following conventions: - Locals starts with `__` and are lowercased. - Rocket modules start with `_` and are lowercased. - `std` types start with `_` and are titlecased. - Rocket types are titlecased. * A `header` module was added to `http`, contains header types. * `SAFETY` is used as doc-string keyword for `unsafe` related comments. * The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
# 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<Query>` and
`UriDisplay<Path>`, and `FromUriParam<Query>` and `FromUriParam<Path>`.
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<Path>` and `FromUriParam<Query>`.
This division has an effect on how the `uri!` macro can be invoked. In query
parts, for a route type of `Option<T>`, 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;
2021-06-15 19:08:36 +00:00
#[get("/<id>/<name>?<age>")]
fn person(id: Option<usize>, name: &str, age: Option<u8>) { /* .. */ }
// Note that `id` is `Option<usize>` 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!`
UTF-8 routes. Forms revamp. Temp files. Capped. So. Many. Changes. This is an insane commit: simultaneously one of the best (because of all the wonderful improvements!) and one of the worst (because it is just massive) in the project's history. Routing: * All UTF-8 characters are accepted everywhere in route paths. (#998) * `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]` becomes `#[route(GET, uri = "..")]`. Forms Revamp * All form related types now reside in a new `form` module. * Multipart forms are supported. (resolves #106) * Collections are supported in forms and queries. (resolves #205) * Nested structures in forms and queries are supported. (resolves #313) * Form fields can be ad-hoc validated with `#[field(validate = expr)]`. * `FromFormValue` is now `FromFormField`, blanket implements `FromForm`. * Form field values are always percent-decoded apriori. Temporary Files * A new `TempFile` data and form guard allows streaming data directly to a file which can then be persisted. * A new `temp_dir` config parameter specifies where to store `TempFile`. * The limits `file` and `file/$ext`, where `$ext` is the file extension, determines the data limit for a `TempFile`. Capped * A new `Capped` type is used to indicate when data has been truncated due to incoming data limits. It allows checking whether data is complete or truncated. * `DataStream` methods return `Capped` types. * `DataStream` API has been revamped to account for `Capped` types. * Several `Capped<T>` types implement `FromData`, `FromForm`. * HTTP 413 (Payload Too Large) errors are now returned when data limits are exceeded. (resolves #972) Hierarchical Limits * Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c` falls back to `a/b` then `a`. Core * `&RawStr` no longer implements `FromParam`. * `&str` implements `FromParam`, `FromData`, `FromForm`. * `FromTransformedData` was removed. * `FromData` gained a lifetime for use with request-local data. * The default error HTML is more compact. * `&Config` is a request guard. * The `DataStream` interface was entirely revamped. * `State` is only exported via `rocket::State`. * A `request::local_cache!()` macro was added for storing values in request-local cache without consideration for type uniqueness by using a locally generated anonymous type. * `Request::get_param()` is now `Request::param()`. * `Request::get_segments()` is now `Request::segments()`, takes a range. * `Request::get_query_value()` is now `Request::query_value()`, can parse any `FromForm` including sequences. * `std::io::Error` implements `Responder` like `Debug<std::io::Error>`. * `(Status, R)` where `R: Responder` implements `Responder` by overriding the `Status` of `R`. * The name of a route is printed first during route matching. * `FlashMessage` now only has one lifetime generic. HTTP * `RawStr` implements `serde::{Serialize, Deserialize}`. * `RawStr` implements _many_ more methods, in particular, those related to the `Pattern` API. * `RawStr::from_str()` is now `RawStr::new()`. * `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as necessary, return `Cow`. * `Status` implements `Default` with `Status::Ok`. * `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`. * Authority and origin part of `Absolute` can be modified with new `Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods. * `Origin::segments()` was removed in favor of methods split into query and path parts and into raw and decoded versions. * The `Segments` iterator is smarter, returns decoded `&str` items. * `Segments::into_path_buf()` is now `Segments::to_path_buf()`. * A new `QuerySegments` is the analogous query segment iterator. * Once set, `expires` on private cookies is not overwritten. (resolves #1506) * `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`. Codegen * Preserve more spans in `uri!` macro. * Preserve spans `FromForm` field types. * All dynamic parameters in a query string must typecheck as `FromForm`. * `FromFormValue` derive removed; `FromFormField` added. * The `form` `FromForm` and `FromFormField` field attribute is now named `field`. `#[form(field = ..)]` is now `#[field(name = ..)]`. Contrib * `Json` implements `FromForm`. * `MsgPack` implements `FromForm`. * The `json!` macro is exported as `rocket_contrib::json::json!`. * Added clarifying docs to `StaticFiles`. Examples * `form_validation` and `form_kitchen_sink` removed in favor of `forms`. * The `hello_world` example uses unicode in paths. * The `json` example only allocates as necessary. Internal * Codegen uses new `exports` module with the following conventions: - Locals starts with `__` and are lowercased. - Rocket modules start with `_` and are lowercased. - `std` types start with `_` and are titlecased. - Rocket types are titlecased. * A `header` module was added to `http`, contains header types. * `SAFETY` is used as doc-string keyword for `unsafe` related comments. * The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
before it is displayed with `UriDisplay`. If a `T: FromUriParam<P, S>`
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<P, &'a str> 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<T>`
The following conversions only apply to path parts:
* `T` to `Option<T>`
* `T` to `Result<T, E>`
UTF-8 routes. Forms revamp. Temp files. Capped. So. Many. Changes. This is an insane commit: simultaneously one of the best (because of all the wonderful improvements!) and one of the worst (because it is just massive) in the project's history. Routing: * All UTF-8 characters are accepted everywhere in route paths. (#998) * `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]` becomes `#[route(GET, uri = "..")]`. Forms Revamp * All form related types now reside in a new `form` module. * Multipart forms are supported. (resolves #106) * Collections are supported in forms and queries. (resolves #205) * Nested structures in forms and queries are supported. (resolves #313) * Form fields can be ad-hoc validated with `#[field(validate = expr)]`. * `FromFormValue` is now `FromFormField`, blanket implements `FromForm`. * Form field values are always percent-decoded apriori. Temporary Files * A new `TempFile` data and form guard allows streaming data directly to a file which can then be persisted. * A new `temp_dir` config parameter specifies where to store `TempFile`. * The limits `file` and `file/$ext`, where `$ext` is the file extension, determines the data limit for a `TempFile`. Capped * A new `Capped` type is used to indicate when data has been truncated due to incoming data limits. It allows checking whether data is complete or truncated. * `DataStream` methods return `Capped` types. * `DataStream` API has been revamped to account for `Capped` types. * Several `Capped<T>` types implement `FromData`, `FromForm`. * HTTP 413 (Payload Too Large) errors are now returned when data limits are exceeded. (resolves #972) Hierarchical Limits * Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c` falls back to `a/b` then `a`. Core * `&RawStr` no longer implements `FromParam`. * `&str` implements `FromParam`, `FromData`, `FromForm`. * `FromTransformedData` was removed. * `FromData` gained a lifetime for use with request-local data. * The default error HTML is more compact. * `&Config` is a request guard. * The `DataStream` interface was entirely revamped. * `State` is only exported via `rocket::State`. * A `request::local_cache!()` macro was added for storing values in request-local cache without consideration for type uniqueness by using a locally generated anonymous type. * `Request::get_param()` is now `Request::param()`. * `Request::get_segments()` is now `Request::segments()`, takes a range. * `Request::get_query_value()` is now `Request::query_value()`, can parse any `FromForm` including sequences. * `std::io::Error` implements `Responder` like `Debug<std::io::Error>`. * `(Status, R)` where `R: Responder` implements `Responder` by overriding the `Status` of `R`. * The name of a route is printed first during route matching. * `FlashMessage` now only has one lifetime generic. HTTP * `RawStr` implements `serde::{Serialize, Deserialize}`. * `RawStr` implements _many_ more methods, in particular, those related to the `Pattern` API. * `RawStr::from_str()` is now `RawStr::new()`. * `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as necessary, return `Cow`. * `Status` implements `Default` with `Status::Ok`. * `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`. * Authority and origin part of `Absolute` can be modified with new `Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods. * `Origin::segments()` was removed in favor of methods split into query and path parts and into raw and decoded versions. * The `Segments` iterator is smarter, returns decoded `&str` items. * `Segments::into_path_buf()` is now `Segments::to_path_buf()`. * A new `QuerySegments` is the analogous query segment iterator. * Once set, `expires` on private cookies is not overwritten. (resolves #1506) * `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`. Codegen * Preserve more spans in `uri!` macro. * Preserve spans `FromForm` field types. * All dynamic parameters in a query string must typecheck as `FromForm`. * `FromFormValue` derive removed; `FromFormField` added. * The `form` `FromForm` and `FromFormField` field attribute is now named `field`. `#[form(field = ..)]` is now `#[field(name = ..)]`. Contrib * `Json` implements `FromForm`. * `MsgPack` implements `FromForm`. * The `json!` macro is exported as `rocket_contrib::json::json!`. * Added clarifying docs to `StaticFiles`. Examples * `form_validation` and `form_kitchen_sink` removed in favor of `forms`. * The `hello_world` example uses unicode in paths. * The `json` example only allocates as necessary. Internal * Codegen uses new `exports` module with the following conventions: - Locals starts with `__` and are lowercased. - Rocket modules start with `_` and are lowercased. - `std` types start with `_` and are titlecased. - Rocket types are titlecased. * A `header` module was added to `http`, contains header types. * `SAFETY` is used as doc-string keyword for `unsafe` related comments. * The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
The following conversions are implemented only in query parts:
* `Option<T>` to `Result<T, E>` (for any `E`)
* `Result<T, E>` to `Option<T>` (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<PathBuf>` is expected:
```rust
# #[macro_use] extern crate rocket;
UTF-8 routes. Forms revamp. Temp files. Capped. So. Many. Changes. This is an insane commit: simultaneously one of the best (because of all the wonderful improvements!) and one of the worst (because it is just massive) in the project's history. Routing: * All UTF-8 characters are accepted everywhere in route paths. (#998) * `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]` becomes `#[route(GET, uri = "..")]`. Forms Revamp * All form related types now reside in a new `form` module. * Multipart forms are supported. (resolves #106) * Collections are supported in forms and queries. (resolves #205) * Nested structures in forms and queries are supported. (resolves #313) * Form fields can be ad-hoc validated with `#[field(validate = expr)]`. * `FromFormValue` is now `FromFormField`, blanket implements `FromForm`. * Form field values are always percent-decoded apriori. Temporary Files * A new `TempFile` data and form guard allows streaming data directly to a file which can then be persisted. * A new `temp_dir` config parameter specifies where to store `TempFile`. * The limits `file` and `file/$ext`, where `$ext` is the file extension, determines the data limit for a `TempFile`. Capped * A new `Capped` type is used to indicate when data has been truncated due to incoming data limits. It allows checking whether data is complete or truncated. * `DataStream` methods return `Capped` types. * `DataStream` API has been revamped to account for `Capped` types. * Several `Capped<T>` types implement `FromData`, `FromForm`. * HTTP 413 (Payload Too Large) errors are now returned when data limits are exceeded. (resolves #972) Hierarchical Limits * Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c` falls back to `a/b` then `a`. Core * `&RawStr` no longer implements `FromParam`. * `&str` implements `FromParam`, `FromData`, `FromForm`. * `FromTransformedData` was removed. * `FromData` gained a lifetime for use with request-local data. * The default error HTML is more compact. * `&Config` is a request guard. * The `DataStream` interface was entirely revamped. * `State` is only exported via `rocket::State`. * A `request::local_cache!()` macro was added for storing values in request-local cache without consideration for type uniqueness by using a locally generated anonymous type. * `Request::get_param()` is now `Request::param()`. * `Request::get_segments()` is now `Request::segments()`, takes a range. * `Request::get_query_value()` is now `Request::query_value()`, can parse any `FromForm` including sequences. * `std::io::Error` implements `Responder` like `Debug<std::io::Error>`. * `(Status, R)` where `R: Responder` implements `Responder` by overriding the `Status` of `R`. * The name of a route is printed first during route matching. * `FlashMessage` now only has one lifetime generic. HTTP * `RawStr` implements `serde::{Serialize, Deserialize}`. * `RawStr` implements _many_ more methods, in particular, those related to the `Pattern` API. * `RawStr::from_str()` is now `RawStr::new()`. * `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as necessary, return `Cow`. * `Status` implements `Default` with `Status::Ok`. * `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`. * Authority and origin part of `Absolute` can be modified with new `Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods. * `Origin::segments()` was removed in favor of methods split into query and path parts and into raw and decoded versions. * The `Segments` iterator is smarter, returns decoded `&str` items. * `Segments::into_path_buf()` is now `Segments::to_path_buf()`. * A new `QuerySegments` is the analogous query segment iterator. * Once set, `expires` on private cookies is not overwritten. (resolves #1506) * `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`. Codegen * Preserve more spans in `uri!` macro. * Preserve spans `FromForm` field types. * All dynamic parameters in a query string must typecheck as `FromForm`. * `FromFormValue` derive removed; `FromFormField` added. * The `form` `FromForm` and `FromFormField` field attribute is now named `field`. `#[form(field = ..)]` is now `#[field(name = ..)]`. Contrib * `Json` implements `FromForm`. * `MsgPack` implements `FromForm`. * The `json!` macro is exported as `rocket_contrib::json::json!`. * Added clarifying docs to `StaticFiles`. Examples * `form_validation` and `form_kitchen_sink` removed in favor of `forms`. * The `hello_world` example uses unicode in paths. * The `json` example only allocates as necessary. Internal * Codegen uses new `exports` module with the following conventions: - Locals starts with `__` and are lowercased. - Rocket modules start with `_` and are lowercased. - `std` types start with `_` and are titlecased. - Rocket types are titlecased. * A `header` module was added to `http`, contains header types. * `SAFETY` is used as doc-string keyword for `unsafe` related comments. * The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
use std::path::PathBuf;
UTF-8 routes. Forms revamp. Temp files. Capped. So. Many. Changes. This is an insane commit: simultaneously one of the best (because of all the wonderful improvements!) and one of the worst (because it is just massive) in the project's history. Routing: * All UTF-8 characters are accepted everywhere in route paths. (#998) * `path` is now `uri` in `route` attribute: `#[route(GET, path = "..")]` becomes `#[route(GET, uri = "..")]`. Forms Revamp * All form related types now reside in a new `form` module. * Multipart forms are supported. (resolves #106) * Collections are supported in forms and queries. (resolves #205) * Nested structures in forms and queries are supported. (resolves #313) * Form fields can be ad-hoc validated with `#[field(validate = expr)]`. * `FromFormValue` is now `FromFormField`, blanket implements `FromForm`. * Form field values are always percent-decoded apriori. Temporary Files * A new `TempFile` data and form guard allows streaming data directly to a file which can then be persisted. * A new `temp_dir` config parameter specifies where to store `TempFile`. * The limits `file` and `file/$ext`, where `$ext` is the file extension, determines the data limit for a `TempFile`. Capped * A new `Capped` type is used to indicate when data has been truncated due to incoming data limits. It allows checking whether data is complete or truncated. * `DataStream` methods return `Capped` types. * `DataStream` API has been revamped to account for `Capped` types. * Several `Capped<T>` types implement `FromData`, `FromForm`. * HTTP 413 (Payload Too Large) errors are now returned when data limits are exceeded. (resolves #972) Hierarchical Limits * Data limits are now hierarchical, delimited with `/`. A limit of `a/b/c` falls back to `a/b` then `a`. Core * `&RawStr` no longer implements `FromParam`. * `&str` implements `FromParam`, `FromData`, `FromForm`. * `FromTransformedData` was removed. * `FromData` gained a lifetime for use with request-local data. * The default error HTML is more compact. * `&Config` is a request guard. * The `DataStream` interface was entirely revamped. * `State` is only exported via `rocket::State`. * A `request::local_cache!()` macro was added for storing values in request-local cache without consideration for type uniqueness by using a locally generated anonymous type. * `Request::get_param()` is now `Request::param()`. * `Request::get_segments()` is now `Request::segments()`, takes a range. * `Request::get_query_value()` is now `Request::query_value()`, can parse any `FromForm` including sequences. * `std::io::Error` implements `Responder` like `Debug<std::io::Error>`. * `(Status, R)` where `R: Responder` implements `Responder` by overriding the `Status` of `R`. * The name of a route is printed first during route matching. * `FlashMessage` now only has one lifetime generic. HTTP * `RawStr` implements `serde::{Serialize, Deserialize}`. * `RawStr` implements _many_ more methods, in particular, those related to the `Pattern` API. * `RawStr::from_str()` is now `RawStr::new()`. * `RawStr::url_decode()` and `RawStr::url_decode_lossy()` only allocate as necessary, return `Cow`. * `Status` implements `Default` with `Status::Ok`. * `Status` implements `PartialEq`, `Eq`, `Hash`, `PartialOrd`, `Ord`. * Authority and origin part of `Absolute` can be modified with new `Absolute::{with,set}_authority()`, `Absolute::{with,set}_origin()` methods. * `Origin::segments()` was removed in favor of methods split into query and path parts and into raw and decoded versions. * The `Segments` iterator is smarter, returns decoded `&str` items. * `Segments::into_path_buf()` is now `Segments::to_path_buf()`. * A new `QuerySegments` is the analogous query segment iterator. * Once set, `expires` on private cookies is not overwritten. (resolves #1506) * `Origin::path()` and `Origin::query()` return `&RawStr`, not `&str`. Codegen * Preserve more spans in `uri!` macro. * Preserve spans `FromForm` field types. * All dynamic parameters in a query string must typecheck as `FromForm`. * `FromFormValue` derive removed; `FromFormField` added. * The `form` `FromForm` and `FromFormField` field attribute is now named `field`. `#[form(field = ..)]` is now `#[field(name = ..)]`. Contrib * `Json` implements `FromForm`. * `MsgPack` implements `FromForm`. * The `json!` macro is exported as `rocket_contrib::json::json!`. * Added clarifying docs to `StaticFiles`. Examples * `form_validation` and `form_kitchen_sink` removed in favor of `forms`. * The `hello_world` example uses unicode in paths. * The `json` example only allocates as necessary. Internal * Codegen uses new `exports` module with the following conventions: - Locals starts with `__` and are lowercased. - Rocket modules start with `_` and are lowercased. - `std` types start with `_` and are titlecased. - Rocket types are titlecased. * A `header` module was added to `http`, contains header types. * `SAFETY` is used as doc-string keyword for `unsafe` related comments. * The `Uri` parser no longer recognizes Rocket route URIs.
2020-10-30 03:50:06 +00:00
#[get("/person/<id>/<details..>")]
fn person(id: usize, details: Option<PathBuf>) { /* .. */ }
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