Aller au contenu

Validation ​

Hono fournit uniquement un validateur très léger. Il peut toutefois devenir puissant lorsqu'il est combiné à un validateur tiers. De plus, la fonctionnalité RPC permet de partager les spécifications de l'API avec vos clients grâce aux types.

Validateur manuel ​

Voyons d'abord comment valider les valeurs reçues sans utiliser de validateur tiers.

Importez validator depuis hono/validator.

ts
import { validator } from 'hono/validator'

Pour valider les données d'un formulaire, indiquez form comme premier argument et un callback comme deuxième argument. Dans ce callback, validez les valeurs et renvoyez les valeurs validées à la fin. Le validator peut être utilisé comme middleware.

ts
app.post(
  '/posts',
  validator('form', (value, c) => {
    const body = value['body']
    if (!body || typeof body !== 'string') {
      return c.text('Invalid!', 400)
    }
    return {
      body: body,
    }
  }),
  //...

Dans le gestionnaire, vous pouvez récupérer la valeur validée avec c.req.valid('form').

ts
, (c) => {
  const { body } = c.req.valid('form')
  // ... do something
  return c.json(
    {
      message: 'Created!',
    },
    201
  )
}

Les cibles de validation comprennent json, query, header, param et cookie, en plus de form.

Attention

Lorsque vous validez json ou form, la requête doit contenir un en-tête content-type correspondant (par exemple Content-Type: application/json pour json). Sinon, le corps de la requête ne sera pas analysé et le callback recevra un objet vide ({}) comme valeur.

Il est important de définir l'en-tête content-type lors des tests avec app.request().

Avec une application comme celle-ci.

ts
const app = new Hono()
app.post(
  '/testing',
  validator('json', (value, c) => {
    // pass-through validator
    return value
  }),
  (c) => {
    const body = c.req.valid('json')
    return c.json(body)
  }
)

Vos tests peuvent s'écrire ainsi.

ts
// ❌ this will not work
const res = await app.request('/testing', {
  method: 'POST',
  body: JSON.stringify({ key: 'value' }),
})
const data = await res.json()
console.log(data) // {}

// ✅ this will work
const res = await app.request('/testing', {
  method: 'POST',
  body: JSON.stringify({ key: 'value' }),
  headers: new Headers({ 'Content-Type': 'application/json' }),
})
const data = await res.json()
console.log(data) // { key: 'value' }

Attention

Lorsque vous validez header, vous devez utiliser un nom en minuscules comme clé.

Pour valider l'en-tête Idempotency-Key, vous devez utiliser idempotency-key comme clé.

ts
// ❌ this will not work
app.post(
  '/api',
  validator('header', (value, c) => {
    // idempotencyKey is always undefined
    // so this middleware always return 400 as not expected
    const idempotencyKey = value['Idempotency-Key']

    if (idempotencyKey == undefined || idempotencyKey === '') {
      throw new HTTPException(400, {
        message: 'Idempotency-Key is required',
      })
    }
    return { idempotencyKey }
  }),
  (c) => {
    const { idempotencyKey } = c.req.valid('header')
    // ...
  }
)

// ✅ this will work
app.post(
  '/api',
  validator('header', (value, c) => {
    // can retrieve the value of the header as expected
    const idempotencyKey = value['idempotency-key']

    if (idempotencyKey == undefined || idempotencyKey === '') {
      throw new HTTPException(400, {
        message: 'Idempotency-Key is required',
      })
    }
    return { idempotencyKey }
  }),
  (c) => {
    const { idempotencyKey } = c.req.valid('header')
    // ...
  }
)

Plusieurs validateurs ​

Vous pouvez également combiner plusieurs validateurs pour valider différentes parties de la requête :

ts
app.post(
  '/posts/:id',
  validator('param', ...),
  validator('query', ...),
  validator('json', ...),
  (c) => {
    //...
  }
)

Avec Zod ​

Vous pouvez utiliser Zod, l'un des validateurs tiers. Nous recommandons l'utilisation d'un validateur tiers.

Installez-le depuis le registre npm.

sh
npm i zod
sh
yarn add zod
sh
pnpm add zod
sh
bun add zod

Importez z depuis zod.

ts
import * as z from 'zod'

Écrivez votre schéma.

ts
const schema = z.object({
  body: z.string(),
})

Vous pouvez utiliser le schéma dans le callback pour effectuer la validation et renvoyer la valeur validée.

ts
const route = app.post(
  '/posts',
  validator('form', (value, c) => {
    const parsed = schema.safeParse(value)
    if (!parsed.success) {
      return c.text('Invalid!', 401)
    }
    return parsed.data
  }),
  (c) => {
    const { body } = c.req.valid('form')
    // ... do something
    return c.json(
      {
        message: 'Created!',
      },
      201
    )
  }
)

Middleware de validation Zod ​

Le middleware de validation Zod simplifie encore les choses.

sh
npm i @hono/zod-validator
sh
yarn add @hono/zod-validator
sh
pnpm add @hono/zod-validator
sh
bun add @hono/zod-validator

Importez ensuite zValidator.

ts
import { zValidator } from '@hono/zod-validator'

Puis écrivez comme suit.

ts
const route = app.post(
  '/posts',
  zValidator(
    'form',
    z.object({
      body: z.string(),
    })
  ),
  (c) => {
    const validated = c.req.valid('form')
    // ... use your validated data
  }
)

Middleware de validation Standard Schema ​

Standard Schema est une spécification qui fournit une interface commune aux bibliothèques de validation TypeScript. Créée par les mainteneurs de Zod, Valibot et ArkType, elle permet aux outils de l'écosystème de fonctionner avec n'importe quelle bibliothèque de validation sans adaptateurs spécifiques.

Le middleware de validation Standard Schema permet d'utiliser avec Hono n'importe quelle bibliothèque compatible Standard Schema. Vous pouvez ainsi choisir votre validateur préféré tout en conservant une sécurité de typage cohérente.

sh
npm i @hono/standard-validator
sh
yarn add @hono/standard-validator
sh
pnpm add @hono/standard-validator
sh
bun add @hono/standard-validator

Importez sValidator depuis le paquet :

ts
import { sValidator } from '@hono/standard-validator'

Avec Zod ​

Vous pouvez utiliser Zod avec le validateur Standard Schema :

sh
npm i zod
sh
yarn add zod
sh
pnpm add zod
sh
bun add zod
ts
import * as z from 'zod'
import { sValidator } from '@hono/standard-validator'

const schema = z.object({
  name: z.string(),
  age: z.number(),
})

app.post('/author', sValidator('json', schema), (c) => {
  const data = c.req.valid('json')
  return c.json({
    success: true,
    message: `${data.name} is ${data.age}`,
  })
})

Avec Valibot ​

Valibot est une alternative légère à Zod avec une conception modulaire :

sh
npm i valibot
sh
yarn add valibot
sh
pnpm add valibot
sh
bun add valibot
ts
import * as v from 'valibot'
import { sValidator } from '@hono/standard-validator'

const schema = v.object({
  name: v.string(),
  age: v.number(),
})

app.post('/author', sValidator('json', schema), (c) => {
  const data = c.req.valid('json')
  return c.json({
    success: true,
    message: `${data.name} is ${data.age}`,
  })
})

Avec ArkType ​

ArkType propose une syntaxe native TypeScript pour la validation à l'exécution :

sh
npm i arktype
sh
yarn add arktype
sh
pnpm add arktype
sh
bun add arktype
ts
import { type } from 'arktype'
import { sValidator } from '@hono/standard-validator'

const schema = type({
  name: 'string',
  age: 'number',
})

app.post('/author', sValidator('json', schema), (c) => {
  const data = c.req.valid('json')
  return c.json({
    success: true,
    message: `${data.name} is ${data.age}`,
  })
})

Publié sous licence MIT.