Web frameworks
Drop-in replacements for ntex::web::types::{Json, Query, Path, Form}, plus header and cookie extractors. Shared behaviour (status codes, error body, coercion, header/cookie rules) is in the web adapters overview.
Install
Cargo.toml
[dependencies]
vld = "0.5"
vld-ntex = "0.5" # ntex 4
ntex = { version = "4", features = ["tokio"] }
For ntex 3:
Cargo.toml
[dependencies]
vld-ntex = { version = "0.5", default-features = false, features = ["ntex-3"] }
ntex = { version = "3", features = ["tokio"] }
Features
| Feature | Default | Description |
|---|---|---|
ntex-4 | yes | Build against ntex 4 |
ntex-3 | no | Build against ntex 3 (disable default features) |
compress | no | Decode Content-Encoding: gzip / deflate / br request bodies (enables ntex's compress) |
Enable exactly one of ntex-3 / ntex-4; both or neither is a compile error. The selected crate is re-exported as vld_ntex::ntex.
MSRV: 1.97 with ntex-4 (the crate's declared rust-version); ntex-3 builds on 1.88 with --ignore-rust-version. See MSRV.
Example
main.rs
use ntex::web::{self, App, HttpResponse, HttpServer};
use vld_ntex::{VldJson, VldPath, VldQuery};
vld::schema! {
#[derive(Debug)]
pub struct CreateUser {
pub name: String => vld::string().min(2).max(50),
pub email: String => vld::string().email(),
}
}
vld::schema! {
#[derive(Debug)]
pub struct UserPath {
pub id: i64 => vld::number().int().min(1),
}
}
vld::schema! {
#[derive(Debug)]
pub struct Search {
pub q: String => vld::string().min(1),
}
}
async fn create_user(user: VldJson<CreateUser>) -> HttpResponse {
HttpResponse::Created().body(format!("created {}", user.name))
}
async fn get_user(path: VldPath<UserPath>) -> HttpResponse {
HttpResponse::Ok().body(format!("user #{}", path.id))
}
async fn search(q: VldQuery<Search>) -> HttpResponse {
HttpResponse::Ok().body(format!("search: {}", q.q))
}
#[ntex::main]
async fn main() -> std::io::Result<()> {
let app = || {
App::new()
.route("/users", web::post().to(create_user))
.route("/users/{id}", web::get().to(get_user))
.route("/search", web::get().to(search))
};
// ntex 4
HttpServer::new(async move |_| app())
.bind("127.0.0.1:8080", ntex::SharedCfg::default())?
.run()
.await
// ntex 3: HttpServer::new(async move || app()).bind("127.0.0.1:8080")?.run().await
}
The full example is crates/vld-ntex/examples/ntex_basic.rs (cargo run -p vld-ntex --example ntex_basic).
API
| Item | Description |
|---|---|
VldJson<T> | JSON body (requires a JSON Content-Type) |
VldQuery<T> | Query string |
VldPath<T> | Path parameters (decoded by ntex's router) |
VldForm<T> | application/x-www-form-urlencoded body |
VldHeaders<T> | Request headers (X-Request-Id → x_request_id) |
VldCookie<T> | Cookies from all Cookie headers |
VldNtexError | Error of every extractor (WebResponseError): status(), body(), error() |
VldBodyLimit | Body size limit for VldJson / VldForm, registered as app state |
ntex | Re-export of the selected ntex crate |
prelude | Everything above plus vld::prelude::* |
Body limit
VldJson and VldForm read the payload themselves up to 2 MiB; ntex's JsonConfig / PayloadConfig do not apply. Register VldBodyLimit as app state:
use vld_ntex::VldBodyLimit;
// ntex 4
App::new().with_config(web::WebAppConfig::new().set_state(VldBodyLimit(8 * 1024 * 1024)));
// ntex 3
App::new().state(VldBodyLimit(8 * 1024 * 1024));
Gotchas
- Without the
compressfeature compressed request bodies are not decoded, so a gzip body fails as malformed JSON (422). With it, the limit applies to the decoded size. - ntex 4 needs a recent compiler (1.97). Pin
ntex-3if your toolchain is older. - The ntex version of
vld-ntexand your ownntexdependency must match, or the extractors will not implement your version'sFromRequest.