[](https://crates.io/crates/vld-ntex)
[](https://docs.rs/vld-ntex)
[](https://github.com/s00d/vld/blob/main/LICENSE)
[](https://github.com/s00d/vld)
[](https://github.com/s00d/vld/issues)
[](https://github.com/s00d/vld/stargazers)
# vld-ntex
[ntex](https://ntex.rs/) integration for the [vld](https://crates.io/crates/vld) validation library.
## Overview
Provides 6 extractors that validate request data using `vld` schemas **before** your handler runs:
| `VldJson<T>` | `ntex::web::types::Json<T>` | JSON request body |
| `VldQuery<T>` | `ntex::web::types::Query<T>` | URL query parameters |
| `VldPath<T>` | `ntex::web::types::Path<T>` | URL path parameters |
| `VldForm<T>` | `ntex::web::types::Form<T>` | URL-encoded form body |
| `VldHeaders<T>` | manual header extraction | HTTP headers |
| `VldCookie<T>` | manual cookie parsing | Cookie values |
On validation failure all extractors return **422 Unprocessable Entity** with a JSON body describing every issue.
## Installation
```toml
[dependencies]
vld = "0.1"
vld-ntex = "0.1"
ntex = "3"
```
## VldJson — JSON body
```rust
use ntex::web::{self, HttpResponse};
use vld_ntex::VldJson;
vld::schema! {
#[derive(Debug)]
pub struct CreateUser {
pub name: String => vld::string().min(2).max(50),
pub email: String => vld::string().email(),
}
}
async fn create_user(body: VldJson<CreateUser>) -> HttpResponse {
HttpResponse::Ok().body(format!("Created: {}", body.name))
}
```
## VldQuery — query parameters
Values are automatically coerced: `"42"` → number, `"true"`/`"false"` → boolean, empty → null.
```rust
use ntex::web::HttpResponse;
use vld_ntex::VldQuery;
vld::schema! {
#[derive(Debug)]
pub struct SearchParams {
pub q: String => vld::string().min(1).max(200),
pub page: Option<i64> => vld::number().int().min(1).optional(),
pub limit: Option<i64> => vld::number().int().min(1).max(100).optional(),
}
}
async fn search(params: VldQuery<SearchParams>) -> HttpResponse {
HttpResponse::Ok().body(format!("Searching '{}' page={:?}", params.q, params.page))
}
```
## VldPath — path parameters
```rust
use ntex::web::{self, HttpResponse};
use vld_ntex::VldPath;
vld::schema! {
#[derive(Debug)]
pub struct UserPath {
pub id: i64 => vld::number().int().min(1),
}
}
async fn get_user(path: VldPath<UserPath>) -> HttpResponse {
HttpResponse::Ok().body(format!("User #{}", path.id))
}
// Register: .route("/users/{id}", web::get().to(get_user))
```
## VldForm — URL-encoded form body
```rust
use ntex::web::HttpResponse;
use vld_ntex::VldForm;
vld::schema! {
#[derive(Debug)]
pub struct LoginForm {
pub username: String => vld::string().min(3).max(50),
pub password: String => vld::string().min(8),
}
}
async fn login(form: VldForm<LoginForm>) -> HttpResponse {
HttpResponse::Ok().body(format!("Welcome, {}!", form.username))
}
```
## VldHeaders — HTTP headers
Header names are normalised to snake_case: `Content-Type` → `content_type`, `X-Request-Id` → `x_request_id`.
```rust
use ntex::web::HttpResponse;
use vld_ntex::VldHeaders;
vld::schema! {
#[derive(Debug)]
pub struct AuthHeaders {
pub authorization: String => vld::string().min(1),
pub x_request_id: Option<String> => vld::string().optional(),
}
}
async fn protected(headers: VldHeaders<AuthHeaders>) -> HttpResponse {
HttpResponse::Ok().body(format!("auth={}", headers.authorization))
}
```
## VldCookie — cookies
Cookie names are matched as-is to schema field names.
```rust
use ntex::web::HttpResponse;
use vld_ntex::VldCookie;
vld::schema! {
#[derive(Debug)]
pub struct Session {
pub session_id: String => vld::string().min(1),
pub theme: Option<String> => vld::string().optional(),
}
}
async fn dashboard(cookies: VldCookie<Session>) -> HttpResponse {
HttpResponse::Ok().body(format!("session={}", cookies.session_id))
}
```
## Combining extractors
Multiple extractors can be used in the same handler:
```rust
use ntex::web::HttpResponse;
use vld_ntex::{VldJson, VldQuery};
vld::schema! {
#[derive(Debug)]
pub struct OrderQuery {
pub dry_run: Option<bool> => vld::boolean().optional(),
}
}
vld::schema! {
#[derive(Debug)]
pub struct OrderBody {
pub product_id: i64 => vld::number().int().min(1),
pub quantity: i64 => vld::number().int().min(1).max(1000),
}
}
async fn create_order(
query: VldQuery<OrderQuery>,
body: VldJson<OrderBody>,
) -> HttpResponse {
HttpResponse::Ok().body(format!(
"product={} qty={} dry_run={:?}",
body.product_id, body.quantity, query.dry_run,
))
}
```
## Running the example
```sh
cargo run -p vld-ntex --example ntex_basic
```
### Example requests
```sh
# VldJson — create user:
curl -s -X POST http://localhost:8080/users \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com", "age": 30}'
# VldPath — get user by id:
curl -s http://localhost:8080/users/42
# VldQuery — search:
curl -s "http://localhost:8080/search?q=rust&page=1"
```
## Error response format
```json
{
"error": "Validation failed",
"issues": [
{ "path": "name", "message": "String must contain at least 2 character(s)", "code": "too_small" }
]
}
```
## License
MIT