rocket

Derive Macro Responder

Source
#[derive(Responder)]
{
    // Attributes available to this derive:
    #[response]
}
Expand description

Derive for the Responder trait.

The Responder derive can be applied to enums and structs with named fields. When applied to enums, variants must have at least one field. When applied to structs, the struct must have at least one field.

#[derive(Responder)]
enum MyResponderA {
    A(String),
    B(File, ContentType),
}

#[derive(Responder)]
struct MyResponderB {
    inner: OtherResponder,
    header: ContentType,
}

§Semantics

The derive generates an implementation of the Responder trait for the decorated enum or structure. The derive uses the first field of a variant or structure to generate a Response. As such, the type of the first field must implement Responder. The remaining fields of a variant or structure are set as headers in the produced Response using Response::set_header(). As such, every other field (unless explicitly ignored, explained next) must implement Into<Header>.

Except for the first field, fields decorated with #[response(ignore)] are ignored by the derive:

#[derive(Responder)]
enum MyResponder {
    A(String),
    B(File, ContentType, #[response(ignore)] Other),
}

#[derive(Responder)]
struct MyOtherResponder {
    inner: NamedFile,
    header: ContentType,
    #[response(ignore)]
    other: Other,
}

Decorating the first field with #[response(ignore)] has no effect.

§Field Attribute

Additionally, the response attribute can be used on named structures and enum variants to override the status and/or content-type of the Response produced by the generated implementation. The response attribute used in these positions has the following grammar:

response := parameter (',' parameter)?

parameter := 'status' '=' STATUS
           | 'content_type' '=' CONTENT_TYPE

STATUS := unsigned integer >= 100 and < 600
CONTENT_TYPE := string literal, as defined by Rust, identifying a valid
                Content-Type, as defined by Rocket

It can be used as follows:

#[derive(Responder)]
enum Error {
    #[response(status = 500, content_type = "json")]
    A(String),
    #[response(status = 404)]
    B(NamedFile, ContentType),
}

#[derive(Responder)]
#[response(status = 400)]
struct MyResponder {
    inner: InnerResponder,
    header: ContentType,
    #[response(ignore)]
    other: Other,
}

The attribute accepts two key/value pairs: status and content_type. The value of status must be an unsigned integer representing a valid status code. The Response produced from the generated implementation will have its status overridden to this value.

The value of content_type must be a valid media-type in top/sub form or shorthand form. Examples include:

  • "text/html"
  • "application/x-custom"
  • "html"
  • "json"
  • "plain"
  • "binary"

See ContentType::parse_flexible() for a full list of available shorthands. The Response produced from the generated implementation will have its content-type overridden to this value.

§Generics

The derive accepts any number of type generics and at most one lifetime generic. If a type generic is present and the generic is used in the first field of a structure, the generated implementation will require a bound of Responder<'r, 'o> for the field type containing the generic. In all other fields, unless ignores, a bound of Into<Header<'o> is added.

For example, for a struct struct Foo<T, H>(Json<T>, H), the derive adds:

  • Json<T>: Responder<'r, 'o>
  • H: Into<Header<'o>>
use rocket::serde::Serialize;
use rocket::serde::json::Json;
use rocket::http::ContentType;
use rocket::response::Responder;

// The bound `T: Responder` will be added.
#[derive(Responder)]
#[response(status = 404, content_type = "html")]
struct NotFoundHtml<T>(T);

// The bound `Json<T>: Responder` will be added.
#[derive(Responder)]
struct NotFoundJson<T>(Json<T>);

// The bounds `Json<T>: Responder, E: Responder` will be added.
#[derive(Responder)]
enum MyResult<T, E> {
    Ok(Json<T>),
    #[response(status = 404)]
    Err(E, ContentType)
}

If a lifetime generic is present, it will be replaced with 'o in the generated implementation impl Responder<'r, 'o>:

// Generates `impl<'r, 'o> Responder<'r, 'o> for NotFoundHtmlString<'o>`.
#[derive(Responder)]
#[response(status = 404, content_type = "html")]
struct NotFoundHtmlString<'a>(&'a str);

Both type generics and lifetime generic may be used:

#[derive(Responder)]
struct SomeResult<'o, T>(Result<T, &'o str>);