Route Attribute & Extractors

#[vespera::route] marks a pub async fn as an HTTP handler. Vespera reads the function signature to extract path parameters, query parameters, request body, and response types for the OpenAPI spec.

Route Attribute Parameters

#[vespera::route(
    get,                              // HTTP method (default: get)
    path = "/{id}",                   // Path suffix (appended to file-based prefix)
    tags = ["users", "admin"],        // OpenAPI tags
    description = "Get user by ID"    // OpenAPI operation description
)]
pub async fn get_user(Path(id): Path<u32>) -> Json<User> { ... }
ParameterTypeDefaultDescription
methodget, post, put, patch, delete, head, optionsgetHTTP method
pathstring""Path suffix appended to the file-based prefix
tagsstring array[]OpenAPI tags for grouping in Swagger UI
descriptionstring""OpenAPI operation description

Extractor to OpenAPI Mapping

Vespera reads your handler's extractor types and maps them to OpenAPI parameters and request bodies automatically:

ExtractorOpenAPI LocationNotes
Path<T>Path parametersT can be a primitive or a struct
Query<T>Query parametersStruct fields become individual query params
Json<T>Request body (application/json)
Form<T>Request body (application/x-www-form-urlencoded)
TypedMultipart<T>Request body (multipart/form-data)Typed with schema
MultipartRequest body (multipart/form-data)Untyped, generic object
TypedHeader<T>Header parameters
State<T>IgnoredInternal — not part of the API
Extension<T>IgnoredInternal — not part of the API

Examples

Path Parameters

// Single path param
#[vespera::route(get, path = "/{id}")]
pub async fn get_user(Path(id): Path<u32>) -> Json<User> { ... }
 
// Multiple path params via struct
#[derive(Deserialize)]
pub struct PostParams {
    pub user_id: u32,
    pub post_id: u32,
}
 
#[vespera::route(get, path = "/{user_id}/posts/{post_id}")]
pub async fn get_post(Path(params): Path<PostParams>) -> Json<Post> { ... }

Query Parameters

#[derive(Deserialize, Schema)]
pub struct ListUsersQuery {
    pub page: Option<u32>,
    pub limit: Option<u32>,
    pub search: Option<String>,
}
 
#[vespera::route(get)]
pub async fn list_users(Query(q): Query<ListUsersQuery>) -> Json<Vec<User>> { ... }

JSON Body

#[derive(Deserialize, Schema)]
pub struct CreateUserRequest {
    pub name: String,
    pub email: String,
}
 
#[vespera::route(post)]
pub async fn create_user(Json(req): Json<CreateUserRequest>) -> Json<User> { ... }

Validated Body (with 422)

use vespera::Validated;
use garde::Validate;
 
#[derive(Deserialize, Schema, Validate)]
pub struct CreateUserRequest {
    #[garde(length(min = 3, max = 32))]
    pub username: String,
    #[garde(email)]
    pub email: String,
}
 
#[vespera::route(post)]
pub async fn create_user(
    Validated(Json(req)): Validated<Json<CreateUserRequest>>,
) -> Json<User> { ... }

State (Ignored by OpenAPI)

#[vespera::route(get)]
pub async fn list_users(
    State(db): State<DbPool>,   // ignored by OpenAPI
    Query(q): Query<ListQuery>, // included in OpenAPI
) -> Json<Vec<User>> { ... }

Error Responses

#[derive(Serialize, Schema)]
pub struct ApiError {
    pub message: String,
}
 
#[vespera::route(get, path = "/{id}")]
pub async fn get_user(
    Path(id): Path<u32>,
) -> Result<Json<User>, (StatusCode, Json<ApiError>)> {
    if id == 0 {
        return Err((
            StatusCode::NOT_FOUND,
            Json(ApiError { message: "Not found".into() }),
        ));
    }
    Ok(Json(User { id, name: "Alice".into() }))
}

Handler Requirements

Contents
Edit this page
문의 및 의견 제출
contact@devfive.kr
Copyright © DEVFIVE. All Rights Reserved.
DEVFIVE