Complete query example
import { Volt, t } from 'voltts';
const app = new Volt();
app.get('/items', (c) => ({ query: c.query }), {
query: t.Object({
limit: t.Optional(t.Integer({ min: 1, max: 100 })),
active: t.Optional(t.Boolean()),
tags: t.Optional(t.Array(t.String())),
}),
});
if (globalThis._importMeta_.main) app.listen(3000);
export default app;Try it
bun run index.ts
curl 'http://localhost:3000/items?limit=20&active=false&tags=coffee&tags=tea'
curl -i 'http://localhost:3000/items?limit=invalid'The first response contains limit 20, active false, and an array of tags. Invalid numeric text produces 400.
Conversion rules
Query and path-parameter schemas enable coercion. Numbers accept nonempty numeric strings; booleans recognize true/false and 1/0 (case-insensitive). Repeated query keys already form an array. Comma-separated strings are not automatically split into arrays. Without a schema query values remain strings or arrays. JSON bodies are not automatically coerced.
POST and path parameter caveat
In the current core, the POST/PUT/PATCH body branch validates the body and headers but does not run query or parameter validation. If those methods need typed URL inputs, call compile(schema, { coerce: true }) explicitly and handle a failed result. Do not rely on GET coercion behavior for all methods.