Validator Middleware
Mware.validator(schema) turns a schema into middleware. It reads each source named in the schema, runs the matching contract, and stores the result on request state for the handler to read.
Registering The Middleware
Pass the middleware to router.use, the same call that registers every other middleware:
import { Define, Mware, Router } from '@neabyte/deserve'
const router = new Router({
routesDir: './routes'
})
const createUser = {
json: Define((body: { name: string }) => ({ name: body.name.trim() }))
}
// Run for every request
router.use(Mware.validator(createUser))
await router.serve(8000)Scoping To A Route
A path prefix limits the validator to matching routes, which follows the rules in Route-Specific Middleware:
// Validate only under /users
router.use('/users', Mware.validator(createUser))For global versus scoped registration in general, see Global Middleware.
Validating Several Sources
A schema can name more than one source, and each contract validates its own slice of the request:
const listUsers = {
// Page number from the query string
query: Define(
(q: Record<string, string>) => ({ page: Number(q['page'] ?? '1') }),
(q) => (/^\d*$/.test(q['page'] ?? '') ? true : 'page must be numeric')
),
// API key from the request headers
headers: Define(
(h: Record<string, string>) => ({ apiKey: h['x-api-key'] ?? '' }),
(h) => (h['x-api-key'] ? true : 'x-api-key header is required')
)
}
// Validate query and headers together
router.use('/users', Mware.validator(listUsers))Several sources validate in the order their keys appear, and the first failing source stops the rest. That order rule lives in Advanced Patterns.

Stacking Validators
Registering more than one validator on the same route merges their results. Each validator adds its own sources to the shared state, so a later read sees every validated source at once:
// Two validators feed one merged state
router.use('/users', Mware.validator(queryRules))
router.use('/users', Mware.validator(bodyRules))The handler reads the merged query and json in one call, shown in Reading Validated Data.
Params Are Rejected Here
A schema that names params throws at registration with Deno.errors.InvalidData. Route params resolve after middleware runs, so the middleware would only ever see an empty object. The error points to the right tool:
import { Define, Mware } from '@neabyte/deserve'
// Throws InvalidData at registration
Mware.validator({
params: Define((p: Record<string, string>) => p)
})Validate params inside the handler with Validator.check instead, covered in Reading Validated Data.
An Empty Schema Is Rejected
A schema with no source contract also throws Deno.errors.InvalidData at registration, since a validator with nothing to validate is a wiring mistake worth catching early:
import { Mware } from '@neabyte/deserve'
// Throws InvalidData, no sources given
Mware.validator({})Both rejections fire when the server starts, not on a request, so a broken schema never reaches production traffic.
Where To Go Next
- Reading Validated Data - read the stored output in a handler.
- Define Schema - shape the contracts a schema points to.
- Advanced Patterns - pick a schema per method on a shared prefix.
- Validation Overview - how the pieces fit together.