Validation
defineHandler enveloppe un handler de route pour ajouter la validation de schéma et l’inférence de types. Il accepte n’importe quelle bibliothèque qui implémente la spec Standard Schema — Zod, Valibot et ArkType fonctionnent tous nativement.
Utilisation de base
Section intitulée « Utilisation de base »import { defineHandler } from 'lacis'import { z } from 'zod'
export const GET = defineHandler({ params: z.object({ id: z.string().uuid() }), query: z.object({ verbose: z.coerce.boolean().optional() }), meta: { summary: 'Obtenir un utilisateur par ID', tags: ['users'] }, handler: async (req, res) => { req.params.id // string — validé et typé req.query.verbose // boolean | undefined — validé et typé res.json({ id: req.params.id }) },})La valeur retournée est une fonction async classique — exportez-la comme tout autre handler de route.
Champs de configuration
Section intitulée « Champs de configuration »params, query, body
Section intitulée « params, query, body »Chaque champ accepte un Standard Schema. Les schémas sont validés dans l’ordre : params en premier, puis query, puis body. Si l’un échoue, Lacis retourne 400 immédiatement.
params— validé contrereq.params(paramètres de chemin URL)query— validé contrereq.query(query string parsée)body— Lacis appellereq.json()en interne et valide le résultat
Attaché à l’opération OpenAPI lors de la génération du spec. Sans effet au moment de la requête.
meta: { summary: 'Créer un utilisateur', description: 'Crée un nouveau compte utilisateur.', tags: ['users'], deprecated: false,}Le handler de requête avec req et res entièrement typés.
Erreurs de validation
Section intitulée « Erreurs de validation »Quand la validation échoue, Lacis envoie un 400 automatiquement :
{ "error": "Validation failed", "issues": [ { "message": "Invalid uuid", "path": ["id"] } ]}Le handler n’est jamais appelé en cas d’échec de validation.
Coercition des query strings
Section intitulée « Coercition des query strings »Les query strings sont toujours des chaînes. Utilisez les utilitaires de coercition de votre validateur :
query: z.object({ page: z.coerce.number().int().positive(), active: z.coerce.boolean().optional(),})import * as v from 'valibot'
query: v.object({ page: v.pipe(v.string(), v.transform(Number), v.integer()), active: v.optional(v.pipe(v.string(), v.transform((s) => s === 'true'))),})import { type } from 'arktype'
query: type({ page: 'number.integer > 0', 'active?': 'boolean' })Validation du body
Section intitulée « Validation du body »import { defineHandler } from 'lacis'import { z } from 'zod'
export const POST = defineHandler({ body: z.object({ name: z.string().min(1), email: z.string().email(), }), meta: { summary: 'Créer un utilisateur', tags: ['users'] }, handler: async (req, res) => { const { name, email } = req.body // entièrement typé res.status(201).json({ name, email }) },})import { defineHandler } from 'lacis'import * as v from 'valibot'
export const POST = defineHandler({ body: v.object({ name: v.pipe(v.string(), v.minLength(1)), email: v.pipe(v.string(), v.email()), }), meta: { summary: 'Créer un utilisateur', tags: ['users'] }, handler: async (req, res) => { const { name, email } = req.body res.status(201).json({ name, email }) },})import { defineHandler } from 'lacis'import { type } from 'arktype'
export const POST = defineHandler({ body: type({ name: 'string > 0', email: 'string.email' }), meta: { summary: 'Créer un utilisateur', tags: ['users'] }, handler: async (req, res) => { const { name, email } = req.body res.status(201).json({ name, email }) },})Schémas combinés
Section intitulée « Schémas combinés »export const PUT = defineHandler({ params: z.object({ id: z.string().uuid() }), query: z.object({ dryRun: z.coerce.boolean().default(false) }), body: z.object({ name: z.string(), email: z.string().email() }), handler: async (req, res) => { if (req.query.dryRun) return res.json({ ok: true, dry: true }) res.json({ id: req.params.id, ...req.body }) },})Inférence de types
Section intitulée « Inférence de types »TypeScript infère les types de sortie de vos schémas. Modifiez un schéma et les types dans handler se mettent à jour automatiquement — aucune annotation manuelle nécessaire.