[][src]Trait rocket::data::FromData

pub trait FromData<'a>: Sized {
    type Error;
    type Owned: Borrow<Self::Borrowed>;
    type Borrowed: ?Sized;
    fn transform(
        request: &Request,
        data: Data
    ) -> Transform<Outcome<Self::Owned, Self::Error>>;
fn from_data(
        request: &Request,
        outcome: Transformed<'a, Self>
    ) -> Outcome<Self, Self::Error>; }

Trait implemented by data guards to derive a value from request body data.

Data Guards

A data guard is a request guard that operates on a request's body data. Data guards validate, parse, and optionally convert request body data. Validation and parsing/conversion is implemented through FromData. In other words, every type that implements FromData is a data guard.

Data guards are used as the target of the data route attribute parameter. A handler can have at most one data guard.

For many data guards, implementing FromDataSimple will be simpler and sufficient. All types that implement FromDataSimple automatically implement FromData. Thus, when possible, prefer to implement FromDataSimple instead of FromData.

Example

In the example below, var is used as the argument name for the data guard type DataGuard. When the submit route matches, Rocket will call the FromData implementation for the type T. The handler will only be called if the guard returns successfully.

#[post("/submit", data = "<var>")]
fn submit(var: DataGuard) { /* ... */ }

Transforming

Data guards can optionally transform incoming data before processing it via an implementation of the FromData::transform() method. This is useful when a data guard requires or could benefit from a reference to body data as opposed to an owned version. If a data guard has no need to operate on a reference to body data, FromDataSimple should be implemented instead; it is simpler to implement and less error prone. All types that implement FromDataSimple automatically implement FromData.

When exercising a data guard, Rocket first calls the guard's FromData::transform() method and then subsequently calls the guard's FromData::from_data() method. Rocket stores data returned by FromData::transform() on the stack. If transform returns a Transform::Owned, Rocket moves the data back to the data guard in the subsequent from_data call as a Transform::Owned. If instead transform returns a Transform::Borrowed variant, Rocket calls borrow() on the owned value, producing a borrow of the associated FromData::Borrowed type and passing it as a Transform::Borrowed.

Example

Consider a data guard type that wishes to hold a slice to two different parts of the incoming data:

struct Name<'a> {
    first: &'a str,
    last: &'a str
}

Without the ability to transform into a borrow, implementing such a data guard would be impossible. With transformation, however, we can instruct Rocket to produce a borrow to a Data that has been transformed into a String (an &str).

use std::io::{self, Read};

use rocket::{Request, Data, Outcome::*};
use rocket::data::{FromData, Outcome, Transform, Transformed};
use rocket::http::Status;

const NAME_LIMIT: u64 = 256;

enum NameError {
    Io(io::Error),
    Parse
}

impl<'a> FromData<'a> for Name<'a> {
    type Error = NameError;
    type Owned = String;
    type Borrowed = str;

    fn transform(_: &Request, data: Data) -> Transform<Outcome<Self::Owned, Self::Error>> {
        let mut stream = data.open().take(NAME_LIMIT);
        let mut string = String::with_capacity((NAME_LIMIT / 2) as usize);
        let outcome = match stream.read_to_string(&mut string) {
            Ok(_) => Success(string),
            Err(e) => Failure((Status::InternalServerError, NameError::Io(e)))
        };

        // Returning `Borrowed` here means we get `Borrowed` in `from_data`.
        Transform::Borrowed(outcome)
    }

    fn from_data(_: &Request, outcome: Transformed<'a, Self>) -> Outcome<Self, Self::Error> {
        // Retrieve a borrow to the now transformed `String` (an &str). This
        // is only correct because we know we _always_ return a `Borrowed` from
        // `transform` above.
        let string = outcome.borrowed()?;

        // Perform a crude, inefficient parse.
        let splits: Vec<&str> = string.split(" ").collect();
        if splits.len() != 2 || splits.iter().any(|s| s.is_empty()) {
            return Failure((Status::UnprocessableEntity, NameError::Parse));
        }

        // Return successfully.
        Success(Name { first: splits[0], last: splits[1] })
    }
}

Outcomes

The returned Outcome of a from_data call determines how the incoming request will be processed.

Provided Implementations

Rocket implements FromData for several built-in types. Their behavior is documented here.

Simplified FromData

For an example of a type that wouldn't require transformation, see the FromDataSimple documentation.

Associated Types

The associated error to be returned when the guard fails.

The owned type returned from FromData::transform().

The trait bounds ensures that it is is possible to borrow an &Self::Borrowed from a value of this type.

The borrowed type consumed by FromData::from_data() when FromData::transform() returns a Transform::Borrowed.

If FromData::from_data() returns a Transform::Owned, this associated type should be set to Self::Owned.

Required Methods

Transforms data into a value of type Self::Owned.

If this method returns a Transform::Owned(Self::Owned), then from_data should subsequently be called with a data value of Transform::Owned(Self::Owned). If this method returns a Transform::Borrowed(Self::Owned), from_data should subsequently be called with a data value of Transform::Borrowed(&Self::Borrowed). In other words, the variant of Transform returned from this method is used to determine which variant of Transform should be passed to the from_data method. Rocket always makes the subsequent call correctly.

It is very unlikely that a correct implementation of this method is capable of returning either of an Owned or Borrowed variant. Instead, this method should return exactly one of these variants.

If transformation succeeds, an outcome of Success is returned. If the data is not appropriate given the type of Self, Forward is returned. On failure, Failure is returned.

Validates, parses, and converts the incoming request body data into an instance of Self.

If validation and parsing succeeds, an outcome of Success is returned. If the data is not appropriate given the type of Self, Forward is returned. If parsing or validation fails, Failure is returned.

Example

When implementing this method, you rarely need to destruct the outcome parameter. Instead, the first line of the method should be one of the following:

// If `Owned` was returned from `transform`:
let data = outcome.owned()?;

// If `Borrowed` was returned from `transform`:
let data = outcome.borrowed()?;

Implementations on Foreign Types

impl<'a, T: FromData<'a> + 'a> FromData<'a> for Result<T, T::Error>
[src]

impl<'a, T: FromData<'a> + 'a> FromData<'a> for Option<T>
[src]

Implementors

impl<'a, T: FromDataSimple> FromData<'a> for T
[src]

impl<'f> FromData<'f> for Data
[src]

The identity implementation of FromData. Always returns Success.

impl<'f, T: FromForm<'f>> FromData<'f> for Form<T>
[src]

Parses a Form from incoming form data.

If the content type of the request data is not application/x-www-form-urlencoded, Forwards the request. If the form data cannot be parsed into a T, a Failure with status code UnprocessableEntity is returned. If the form string is malformed, a Failure with status code BadRequest is returned. Finally, if reading the incoming stream fails, returns a Failure with status code InternalServerError. In all failure cases, the raw form string is returned if it was able to be retrieved from the incoming stream.

All relevant warnings and errors are written to the console in Rocket logging format.

impl<'f, T: FromForm<'f>> FromData<'f> for LenientForm<T>
[src]