Rapina Rapina /Tutorial
Read the docs

Validation

Rapina uses the Validated<T> extractor to validate incoming requests. If validation fails, it automatically returns a 422 Unprocessable Entity response with details about what went wrong — your handler never runs.

Validation rules are declared on your request struct using the validator crate's derive macros:

#[derive(Deserialize, Validate, JsonSchema)]
struct CreateUserRequest {
    #[validate(length(min = 1, max = 100))]
    name: String,
    #[validate(email)]
    email: String,
}

Then wrap your extractor with Validated:

async fn handler(Validated(Json(body)): Validated<Json<CreateUserRequest>>)

Assignment

  1. Add the Validate derive to CreateUserRequest
  2. Add #[validate(length(min = 1))] to name and #[validate(email)] to email
  3. Change the extractor from Json(body) to Validated(Json(body)) with Validated<Json<CreateUserRequest>>
Show answer
use rapina::prelude::*;

#[derive(Deserialize, Validate, JsonSchema)]
struct CreateUserRequest {
    #[validate(length(min = 1, max = 100))]
    name: String,
    #[validate(email)]
    email: String,
}

#[derive(Serialize, JsonSchema)]
struct CreateUserResponse {
    id: u64,
    name: String,
}

#[public]
#[post("/users")]
async fn create_user(
    Validated(Json(body)): Validated<Json<CreateUserRequest>>,
) -> Json<CreateUserResponse> {
    Json(CreateUserResponse {
        id: 1,
        name: body.name,
    })
}
Tests
All tests passing — nice work!
main.rs
Response Preview
Complete the tests to see the response preview.
Previous 3 / 6 Next