Skip to content

Commit

Permalink
Improve wrapping responders guide section.
Browse files Browse the repository at this point in the history
  • Loading branch information
aznszn authored and SergioBenitez committed Aug 27, 2024
1 parent 72c9195 commit 5ec0a7c
Showing 1 changed file with 36 additions and 26 deletions.
62 changes: 36 additions & 26 deletions docs/guide/06-responses.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,20 @@ responses according to the incoming `Request` they are responding to.

### Wrapping

Before we describe a few responders, we note that it is typical for responders
to _wrap_ other responders. That is, responders can be of the following form,
where `R` is some type that implements `Responder`:
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);
struct WrappingResponder<R: Responder>(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
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
`202 - Accepted`. It can be used as follows:

```rust
Expand All @@ -47,15 +49,17 @@ 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))
}
```

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`]:
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;
Expand All @@ -70,21 +74,25 @@ fn json() -> status::Custom<content::RawJson<&'static str>> {

! 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:
! note: There are simpler alternatives for setting a status and content-types.

```rust
# #[macro_use] extern crate rocket;
use rocket::http::{Status, ContentType};
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:

#[get("/")]
fn json() -> (Status, (ContentType, &'static str)) {
(Status::ImATeapot, (ContentType::JSON, "{ \"hi\": \"world\" }"))
}
```
```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]:
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;
Expand All @@ -100,10 +108,12 @@ fn json() -> RawTeapotJson {
```

[`Accepted`]: @api/master/rocket/response/status/struct.Accepted.html
[`content::Json`]: @api/master/rocket/response/content/struct.Json.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/

### Errors

Expand Down

0 comments on commit 5ec0a7c

Please sign in to comment.