Chapter 9

Validation

Validate incoming data before handlers use it.

Validation

Validation keeps route handlers small and protects them from unexpected input. Hono's validator() function runs as middleware before the handler.

import { validator } from 'hono/validator'

Validate JSON

The validator callback receives the parsed value for a target such as json, form, query, header, cookie, or param.

app.post(
  '/api/chapters',
  validator('json', (value, c) => {
    const title = value.title

    if (typeof title !== 'string' || title.trim() === '') {
      return c.json({ error: 'Title is required' }, 400)
    }

    return {
      title: title.trim(),
    }
  }),
  (c) => {
    const chapter = c.req.valid('json')
    return c.json({ chapter }, 201)
  }
)

If the validator returns a response, Hono stops and sends that response. If it returns data, the handler can read it with c.req.valid().

Validate forms

The same pattern works for form submissions.

app.post(
  '/subscribe',
  validator('form', (value, c) => {
    const email = value.email

    if (typeof email !== 'string' || !email.includes('@')) {
      return c.text('A valid email is required', 400)
    }

    return { email }
  }),
  (c) => {
    const { email } = c.req.valid('form')
    return c.text(`Subscribed ${email}`)
  }
)

For larger apps, you can pair Hono validation with schema libraries. The important habit is the same: validate at the route boundary, then keep the handler focused on application behavior.