Rocket
Rocket copied to clipboard
Validate non form-encoded body content
Rocket has validation for Forms (rocket::form::validate
), but when accepting other body content (e.g. JSON), there is no way to validate fields of the Deserialize
d object, e.g.
#[derive(Deserialize)]
struct Polygon {
// if this were a FromForm, we could do `#[field(validate = range(3..)]`
num_sides: u32,
}
#[post("/submit-polygon", data = "<polygon>")]
fn submit(polygon: Json<Polygon>) -> String {
format!("polygon has {} sides", polygon.num_sides)
}
Polygons shouldn't be allowed to have less than 3 sides, but there is no simple way to enforce this. Ideally we could do something similar to form validation, with field attributes.
Why this feature can't or shouldn't live outside of Rocket
This could possibly be implemented outside of Rocket using some Validate
derive and a Valid<T>
guard that will only pass if validation succeeds, but that is less than ideal.
Ideal Solution
Ideally, the form-validation logic could be pulled out into its own independent trait, so that you can derive it on any type:
use rocket::Validated;
#[derive(Deserialize, Validated)]
struct Polygon {
#[validate(range = (3..))]
num_sides: u32,
}
// would also work on forms:
#[derive(FromForm, Validated)]
struct FooForm<'a> {
#[validate(omits = "password")]
password: &'a str,
}
Polygons shouldn't be allowed to have less than 3 sides, but there is no simple way to enforce this. Ideally we could do something similar to form validation, with field attributes.
Yeah, there's nothing as simple as rocket's field
attribute, but for posterity, the likely most straightforward approach would be to use serde's deserialize_with
field attribute.
In general, I have some ideas about how to improve/unify data input/output that would include unifying validation across all data handled by a Rocket application. My hope is to write down a spec for the idea soon. Until then, consider this accepted.
Related https://github.com/SergioBenitez/Rocket/discussions/2110.