Web frameworks
Poem extractors that validate JSON bodies, query strings, path parameters, forms, headers and cookies with vld schemas.

Validated FromRequest extractors for Poem. Shared behaviour (status codes, error body, coercion, header/cookie rules) is in the web adapters overview.

Install

Cargo.toml
[dependencies]
vld = "0.5"
vld-poem = "0.5"
poem = "3"

No features. Works with poem 3. MSRV 1.85 (see MSRV).

Example

main.rs
use poem::{get, handler, listener::TcpListener, post, EndpointExt, Route, Server};
use vld_poem::prelude::*;

vld::schema! {
    #[derive(Debug, Clone)]
    pub struct CreateUser {
        pub name: String => vld::string().min(2).max(50),
        pub email: String => vld::string().email(),
    }
}

vld::schema! {
    #[derive(Debug, Clone)]
    pub struct UserPath {
        pub id: i64 => vld::number().int().min(1),
    }
}

#[handler]
async fn create_user(user: VldJson<CreateUser>) -> String {
    format!("created {}", user.name)
}

#[handler]
async fn get_user(p: VldPath<UserPath>) -> String {
    format!("user #{}", p.id)
}

#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
    let app = Route::new()
        .at("/users", post(create_user).data(VldBodyLimit(64 * 1024)))
        .at("/users/:id", get(get_user));

    Server::new(TcpListener::bind("0.0.0.0:3000")).run(app).await
}

The full example is crates/vld-poem/examples/poem_basic.rs (cargo run -p vld-poem --example poem_basic).

API

ItemDescription
VldJson<T>JSON body (requires a JSON Content-Type)
VldQuery<T>Query string
VldPath<T>Route parameters (/users/:id)
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
VldPoemErrorError of every extractor (ResponseError): status(), body(), error()
VldBodyLimitBody size limit for VldJson / VldForm, attached with .data(..)
preludeEverything above plus vld::prelude::*

Extractor types need T: Send + Sync + 'static; all implement Deref / DerefMut to T.

Gotchas

  • Body limit: 2 MiB unless a VldBodyLimit is attached as request data — .data(VldBodyLimit(n)) on an endpoint, route or the whole app.
  • VldPath reads the matched route parameters. Before 0.5 it read the query string, so /users/42?id=7 validated id = 7; see the changelog.
  • Compressed request bodies are not decoded by the extractor; decode them in a middleware first if clients send them.