Trait rocket::form::FromFormField[][src]

pub trait FromFormField<'v>: Send + Sized {
    fn from_value(field: ValueField<'v>) -> Result<'v, Self> { ... }
#[must_use] fn from_data<'life0, 'async_trait>(
        field: DataField<'v, 'life0>
    ) -> Pin<Box<dyn Future<Output = Result<'v, Self>> + Send + 'async_trait>>
    where
        'v: 'async_trait,
        'life0: 'async_trait,
        Self: 'async_trait
, { ... }
fn default() -> Option<Self> { ... } }
Expand description

Implied form guard (FromForm) for parsing a single form field.

Types that implement FromFormField automatically implement FromForm via a blanket implementation. As such, all FromFormField types are form guards and can appear as the type of values in derived FromForm struct fields:

#[derive(FromForm)]
struct Person<'r> {
    name: &'r str,
    age: u16
}

Deriving

FromFormField can be derived for C-like enums, where the generated implementation case-insensitively parses fields with values equal to the name of the variant or the value in field(value = "...").

/// Fields with value `"simple"` parse as `Kind::Simple`. Fields with value
/// `"fancy"` parse as `Kind::SoFancy`.
#[derive(FromFormField)]
enum Kind {
    Simple,
    #[field(value = "fancy")]
    SoFancy,
}

Provided Implementations

See FromForm for a list of all form guards, including those implemented via FromFormField.

Implementing

Implementing FromFormField requires implementing one or both of from_value or from_data, depending on whether the type can be parsed from a value field (text) and/or streaming binary data. Typically, a value can be parsed from either, either directly or by using request-local cache as an intermediary, and parsing from both should be preferred when sensible.

FromFormField is an async trait, so implementations must be decorated with an attribute of #[rocket::async_trait]:

use rocket::form::{self, FromFormField, DataField, ValueField};

#[rocket::async_trait]
impl<'r> FromFormField<'r> for MyType {
    fn from_value(field: ValueField<'r>) -> form::Result<'r, Self> {
        todo!("parse from a value or use default impl")
    }

    async fn from_data(field: DataField<'r, '_>) -> form::Result<'r, Self> {
        todo!("parse from a value or use default impl")
    }
}

Example

The following example parses a custom Person type with the format $name:$data, where $name is expected to be string and data is expected to be any slice of bytes.

use rocket::data::ToByteUnit;
use rocket::form::{self, FromFormField, DataField, ValueField};

use memchr::memchr;

struct Person<'r> {
    name: &'r str,
    data: &'r [u8]
}

#[rocket::async_trait]
impl<'r> FromFormField<'r> for Person<'r> {
    fn from_value(field: ValueField<'r>) -> form::Result<'r, Self> {
        match field.value.find(':') {
            Some(i) => Ok(Person {
                name: &field.value[..i],
                data: field.value[(i + 1)..].as_bytes()
            }),
            None => Err(form::Error::validation("does not contain ':'"))?
        }
    }

    async fn from_data(field: DataField<'r, '_>) -> form::Result<'r, Self> {
        // Retrieve the configured data limit or use `256KiB` as default.
        let limit = field.request.limits()
            .get("person")
            .unwrap_or(256.kibibytes());

        // Read the capped data stream, returning a limit error as needed.
        let bytes = field.data.open(limit).into_bytes().await?;
        if !bytes.is_complete() {
            Err((None, Some(limit)))?;
        }

        // Store the bytes in request-local cache and split at ':'.
        let bytes = bytes.into_inner();
        let bytes = rocket::request::local_cache!(field.request, bytes);
        let (raw_name, data) = match memchr(b':', bytes) {
            Some(i) => (&bytes[..i], &bytes[(i + 1)..]),
            None => Err(form::Error::validation("does not contain ':'"))?
        };

        // Try to parse the name as UTF-8 or return an error if it fails.
        let name = std::str::from_utf8(raw_name)?;
        Ok(Person { name, data })
    }
}

use rocket::form::{Form, FromForm};

// The type can be used directly, if only one field is expected...
#[post("/person", data = "<person>")]
fn person(person: Form<Person<'_>>) { /* ... */ }

// ...or as a named field in another form guard...
#[derive(FromForm)]
struct NewPerson<'r> {
    person: Person<'r>
}

#[post("/person", data = "<person>")]
fn new_person(person: Form<NewPerson<'_>>) { /* ... */ }

Provided methods

Parse a value of T from a form value field.

The default implementation returns an error of ValueField::unexpected().

Parse a value of T from a form data field.

The default implementation returns an error of DataField::unexpected().

Returns a default value, if any exists, to be used during lenient parsing when the form field is missing.

A return value of None means that field is required to exist and parse successfully, always. A return value of Some(default) means that default should be used when a field is missing.

The default implementation returns None.

Implementations on Foreign Types

Implementors

This is supported on crate feature uuid only.
This is supported on crate feature json only.
This is supported on crate feature msgpack only.