Rapina Rapina /Tutorial
Read the docs

Error Handling

Rapina standardizes error responses across your API. Every error includes a machine-readable code, a human message, and a trace_id for debugging. You define your errors as enums with the IntoApiError derive:

#[derive(IntoApiError)]
enum UserError {
    #[api_error(status = 404, message = "User not found")]
    NotFound,
}

When you return Err(UserError::NotFound), Rapina produces:

{
  "error": {
    "code": "NOT_FOUND",
    "message": "User not found",
    "trace_id": "req_abc123"
  }
}

Handlers return Result<T, YourError> and Rapina does the rest.

Assignment

  1. Create a UserError enum with the IntoApiError derive
  2. Add a NotFound variant with #[api_error(status = 404, message = "User not found")]
  3. Change the handler return type to Result<Json<UserResponse>, UserError>
  4. Add a check: if id == 0, return Err(UserError::NotFound)
Show answer
use rapina::prelude::*;

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

#[derive(IntoApiError)]
enum UserError {
    #[api_error(status = 404, message = "User not found")]
    NotFound,
}

#[public]
#[get("/users/:id")]
async fn get_user(Path(id): Path<u64>) -> Result<Json<UserResponse>, UserError> {
    if id == 0 {
        return Err(UserError::NotFound);
    }

    Ok(Json(UserResponse {
        id,
        name: "Alice".into(),
    }))
}
Tests
All tests passing — nice work!
main.rs
Response Preview
Complete the tests to see the response preview.
Previous 4 / 6 Next