Schema validation
ctx.body.json(schema) accepts three validator shapes, detected in this order. All three throw IngeniumValidationError with a fields: Record<string, string> map on failure.
The three accepted shapes
// 1. Standard Schema v1 (any validator with ["~standard"])
import { type } from 'arktype'
const User = type({ name: 'string', email: 'string' })
app.post('/users', async (ctx) => ctx.body.json(User))
// 2. Zod-like safeParse
import { z } from 'zod'
const User = z.object({ name: z.string(), email: z.string().email() })
app.post('/users', async (ctx) => ctx.body.json(User))
// 3. Plain { parse(input): T }
const User = {
parse(input: unknown): { name: string } {
if (typeof input !== 'object') throw new Error('expected object')
return input as { name: string }
},
}
app.post('/users', async (ctx) => ctx.body.json(User))
Failure shape
All three throw IngeniumValidationError (HTTP 422) with:
message: string- a summary.fields: Record<string, string>- field-path to error-message map.
Standard Schema v1 issues with structured paths are dot-joined (['user', 'email'] → 'user.email').
Catching validation errors
app.onError((err, ctx) => {
if (err instanceof IngeniumValidationError) {
return ctx.json({ error: err.message, fields: err.fields }, 422)
}
throw err
})
Known gaps
ctx.query.parse(schema)does not exist yet - only body validation has the schema affordance. Tracked in the roadmap.ExtractParamsdoes not narrow constrained params (:id(\\d+)staysstring).- A TypeBox-specific bridge is deferred - Standard Schema covers it today, but a tighter integration may land later.
Where to next?
- Body parsing - the parser surface.
- Errors -
IngeniumValidationErrorhandling. - IngeniumContext -
ctx.bodyand friends. - Roadmap - query validation status.