Validated Query Extractor (`VQuery<T>`)
Validated Query Extractor (VQuery<T>)
When handling GET requests, we often extract parameters from URL query strings for pagination, sorting, and filtering (e.g., /users?page_num=1&page_size=20).
Like request body validation, validating query parameters is crucial to prevent invalid input from causing errors or security vulnerabilities.
We created a custom Axum extractor — VQuery<T> (Validated Query), combining query parameter parsing and data validation into one step.
Core Concept
If your handler code executes, the data in VQuery is guaranteed to be valid query parameters that have passed all validation rules.
How to Use VQuery<T>
Step 1: Define Your Query Struct
use serde::Deserialize;
use validator::Validate;
#[derive(Deserialize, Validate)]
pub struct PaginationParams {
// ... field definitions
}Step 2: Add Validation Annotations
#[derive(Deserialize, Validate)]
pub struct PaginationParams {
#[validate(range(min = 1, message = "Page number must be > 0"))]
pub page_num: u64,
#[validate(range(min = 1, max = 100, message = "Page size must be 1-100"))]
pub page_size: u64,
pub keyword: Option<String>,
}Step 3: Use VQuery<T> in Handler
use crate::common::validatedquery::VQuery;
pub async fn list_articles(
VQuery(params): VQuery<PaginationParams>,
) -> Response {
// params.page_num and params.page_size are guaranteed valid
ArticleService::list(params).await
}Core Advantages
- Clean Code: Validation from handlers
- Separation of Concerns: Data validation belongs to the data structure
- Secure by Default: Mandatory validation when using
VQuery - Unified Error Handling: Consistent error format for all validation failures
Implementation: FromRequestParts & Deref
VQuery implements Axum's FromRequestParts trait (since query parameters are part of the URI, not the body). We also implement Deref for convenient field access without unwrapping.