Validation
Key points (written by a model)
- Hono ships only a very thin validator, but combining it with a third-party validator is powerful and lets RPC share API specs via types.
- The validator middleware targets json, form, query, header, param and cookie, and the handler reads the validated value via c.req.valid.
- Validating json or form requires a matching content-type header, otherwise the callback receives an empty object.
- For header validation the key must be lowercase, so Idempotency-Key is accessed as idempotency-key.
- Multiple validators can be chained to validate different parts of a request, such as param, query and json.
Model-written
contextclaimmethodsetupresultlimitation
Validation
Hono's thin Validator becomes powerful with third-party validators
Hono provides only a very thin Validator. However, it can be powerful when combined with a third-party Validator. In addition, the RPC feature allows you to share API specifications with your clients through types.Hono provides only a very thin Validator. However, it can be powerful when combined with a third-party Validator.Hono's Validator is thin but strong with third-party validators RPC also shares API types with clientsHono's Validator is thin but strong with third-party validatorsHono's Validator
Manual validator
The validator middleware checks request parts without third-party libraries
First, introduce a way to validate incoming values without using the third-party Validator.First, introduce a way to validate incoming values without using the third-party Validator.Manual validation works without a third-party ValidatorManual validation works without a third-party ValidatorManual validation
Import validator from hono/validator.Import validator from hono/validator.Import validator from hono/validatorImport validator from hono/validatorvalidator import
import { validator } from 'hono/validator'To validate form data, specify form as the first argument and a callback as the second argument.
In the callback, validates the value and return the validated values at the end.
The validator can be used as middleware.To validate form data, specify form as the first argument and a callback as the second argument. In the callback, validates the value and return the validated values at the end. The validator can be used as middleware.validator takes a target and callback, returning validated values It runs as middleware, so handlers receive only validated datavalidator takes a target and callback, returning validated valuesvalidator callback
app.post(
'/posts',
validator('form', (value, c) => {
const body = value['body']
if (!body || typeof body !== 'string') {
return c.text('Invalid!', 400)
}
return {
body: body,
}
}),
//...Within the handler, you can get the validated value with c.req.valid('form').Within the handler, you can get the validated value with c.req.valid('form').Read validated values with c.req.valid('form')Read validated values with c.req.valid('form')c.req.valid('form')
, (c) => {
const { body } = c.req.valid('form')
// ... do something
return c.json(
{
message: 'Created!',
},
201
)
}Validation targets include json, query, header, param and cookie in addition to form.Validation targets include json, query, header, param and cookie in addition to form.Targets include json, query, header, param and cookieTargets include json, query, header, param and cookievalidation targets
Warning
When you validate json or form, the request must contain a matching content-type header (e.g. Content-Type: application/json for json). Otherwise, the request body will not be parsed and you will receive an empty object ({}) as value in the callback.When you validate json or form, the request must contain a matching content-type header (e.g. Content-Type: application/json for json). Otherwise, the request body will not be parsed and you will receive an empty object ({}) as value in the callback.json and form validation need a matching content-type header Without it the body is not parsed and the callback receives an empty objectjson and form validation need a matching content-type headercontent-type header
It is important to set the content-type header when testing using
app.request().It is important to set the content-type header when testing using app.request().Set content-type when testing with app.request()Set content-type when testing with app.request()app.request()
Given an application like this.Given an application like this.A sample app uses a pass-through json validatorA sample app uses a pass-through json validatorpass-through validator
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)
}
)Your tests can be written like this.Your tests can be written like this.Omitting the header returns an empty object in tests Adding Content-Type: application/json makes the test return the body valueOmitting the header returns an empty object in testsempty object
// ❌ 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' }Warning
When you validate header, you need to use lowercase name as the key.When you validate header, you need to use lowercase name as the key.header validation keys must be lowercaseheader validation keys must be lowercaselowercase keys
If you want to validate the Idempotency-Key header, you need to use idempotency-key as the key.If you want to validate the Idempotency-Key header, you need to use idempotency-key as the key.Use idempotency-key, not Idempotency-Key, as the header key Mismatched case leaves the value undefined so the middleware always returns 400Use idempotency-key, not Idempotency-Key, as the header keyidempotency-key
// ❌ 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')
// ...
}
)Multiple validators
Multiple validators can each check a different request part
You can also include multiple validators to validate different parts of request:You can also include multiple validators to validate different parts of request:Chain multiple validators, one per request partChain multiple validators, one per request partMultiple validators
app.post(
'/posts/:id',
validator('param', ...),
validator('query', ...),
validator('json', ...),
(c) => {
//...
}
)With Zod
Zod schemas validate manually inside the validator callback
You can use Zod, one of third-party validators. We recommend using a third-party validator.You can use Zod, one of third-party validators. We recommend using a third-party validator.Zod is a recommended third-party validator It is one of several external validators that strengthen Hono's thin oneZod is a recommended third-party validatorZod
Install from the Npm registry.Install from the Npm registry.Install zod from the Npm registryInstall zod from the Npm registryzod install
npm i zodyarn add zodpnpm add zodbun add zodImport z from zod.Import z from zod.Import z from zodImport z from zodz import
import * as z from 'zod'Write your schema.Write your schema.Define a schema with z.objectDefine a schema with z.objectz.object
const schema = z.object({
body: z.string(),
})You can use the schema in the callback function for validation and return the validated value.You can use the schema in the callback function for validation and return the validated value.Use schema.safeParse in the callback and return parsed.data Failed parses return a 401 text response instead of dataUse schema.safeParse in the callback and return parsed.datasafeParse
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
)
}
)Zod Validator Middleware
zValidator wraps a Zod schema into ready middleware
You can use the Zod Validator Middleware to make it even easier.You can use the Zod Validator Middleware to make it even easier.Zod Validator Middleware makes Zod validation easierZod Validator Middleware makes Zod validation easierZod Validator Middleware
npm i @hono/zod-validatoryarn add @hono/zod-validatorpnpm add @hono/zod-validatorbun add @hono/zod-validatorAnd import zValidator.And import zValidator.Import zValidator from @hono/zod-validatorImport zValidator from @hono/zod-validatorzValidator import
import { zValidator } from '@hono/zod-validator'And write as follows.And write as follows.zValidator takes the target and a Zod schema The handler then reads typed data via c.req.validzValidator takes the target and a Zod schemazValidator usage
const route = app.post(
'/posts',
zValidator(
'form',
z.object({
body: z.string(),
})
),
(c) => {
const validated = c.req.valid('form')
// ... use your validated data
}
)Standard Schema Validator Middleware
sValidator accepts any Standard Schema library with consistent types
Standard Schema is a specification that provides a common interface for TypeScript validation libraries. It was created by the maintainers of Zod, Valibot, and ArkType to allow ecosystem tools to work with any validation library without needing custom adapters.Standard Schema is a specification that provides a common interface for TypeScript validation libraries. It was created by the maintainers of Zod, Valibot, and ArkType to allow ecosystem tools to work with any validation library without needing custom adapters.Standard Schema is a common interface for TS validation libraries Zod, Valibot and ArkType maintainers created it so tools need no custom adaptersStandard Schema is a common interface for TS validation librariesStandard Schema
The Standard Schema Validator Middleware lets you use any Standard Schema-compatible validation library with Hono, giving you the flexibility to choose your preferred validator while maintaining consistent type safety.The Standard Schema Validator Middleware lets you use any Standard Schema-compatible validation library with Hono, giving you the flexibility to choose your preferred validator while maintaining consistent type safety.sValidator supports any Standard Schema library with consistent type safety You choose your preferred validator while Hono keeps type safetysValidator supports any Standard Schema library with consistent type safetysValidator
npm i @hono/standard-validatoryarn add @hono/standard-validatorpnpm add @hono/standard-validatorbun add @hono/standard-validatorImport sValidator from the package:Import sValidator from the package:Import sValidator from @hono/standard-validatorImport sValidator from @hono/standard-validatorsValidator import
import { sValidator } from '@hono/standard-validator'With Zod
Zod works with sValidator through Standard Schema
You can use Zod with the Standard Schema validator:You can use Zod with the Standard Schema validator:Zod schemas pass directly to sValidator The handler reads the validated json through c.req.validZod schemas pass directly to sValidatorZod schema
npm i zodyarn add zodpnpm add zodbun add zodimport * 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}`,
})
})With Valibot
Valibot, a lightweight Zod alternative, works with sValidator
Valibot is a lightweight alternative to Zod with a modular design:Valibot is a lightweight alternative to Zod with a modular design:Valibot schemas work with sValidator the same wayValibot schemas work with sValidator the same wayValibot schema
npm i valibotyarn add valibotpnpm add valibotbun add valibotimport * 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}`,
})
})With ArkType
ArkType's TypeScript-native syntax works with sValidator
ArkType offers TypeScript-native syntax for runtime validation:ArkType offers TypeScript-native syntax for runtime validation:ArkType's type syntax works with sValidatorArkType's type syntax works with sValidatorArkType syntax
npm i arktypeyarn add arktypepnpm add arktypebun add arktypeimport { 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}`,
})
})