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.
UserError enum with the IntoApiError deriveNotFound variant with #[api_error(status = 404, message = "User not found")]Result<Json<UserResponse>, UserError>id == 0, return Err(UserError::NotFound)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(),
}))
}