バリデーション
Hono は、非常に薄いバリデーターのみを提供します。 ただし、サードパーティのバリデーターと組み合わせると、強力な機能を実現できます。 また、RPC 機能を使うと、型を通じてクライアントと API の仕様を共有できます。
手動のバリデーター
まず、サードパーティのバリデーターを使わず、入力値を検証する方法を紹介します。
hono/validator から validator をインポートします。
import { validator } from 'hono/validator'フォームデータを検証するには、第 1 引数に form、第 2 引数にコールバックを指定します。 コールバック内で値を検証し、最後に検証済みの値を返します。 validator はミドルウェアとして使えます。
app.post(
'/posts',
validator('form', (value, c) => {
const body = value['body']
if (!body || typeof body !== 'string') {
return c.text('Invalid!', 400)
}
return {
body: body,
}
}),
//...ハンドラー内では、c.req.valid('form') で検証済みの値を取得できます。
, (c) => {
const { body } = c.req.valid('form')
// ... do something
return c.json(
{
message: 'Created!',
},
201
)
}form のほかに、json、query、header、param、cookie を検証対象にできます。
注意
json や form を検証する場合、リクエストには対応する content-type ヘッダーが必要です(json の場合は Content-Type: application/json など)。なければリクエストボディは解析されず、コールバックには空のオブジェクト({})が渡されます。
次のメソッドでテストする際は、content-type ヘッダーを設定することが重要です。 app.request()。
次のようなアプリケーションがあるとします。
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)
}
)テストは次のように記述できます。
// ❌ 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' }注意
header を検証する際は、キーとして小文字の名前を使う必要があります。
Idempotency-Key ヘッダーを検証するには、キーに idempotency-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')
// ...
}
)複数のバリデーター
複数のバリデーターを使い、リクエストの異なる部分を検証することもできます。
app.post(
'/posts/:id',
validator('param', ...),
validator('query', ...),
validator('json', ...),
(c) => {
//...
}
)Zod の使用
サードパーティのバリデーターの 1 つである Zod を使えます。 サードパーティのバリデーターの利用を推奨します。
npm レジストリからインストールします。
npm i zodyarn add zodpnpm add zodbun add zodzod から z をインポートします。
import * as z from 'zod'スキーマを記述します。
const schema = z.object({
body: z.string(),
})コールバック関数でスキーマを使って検証し、検証済みの値を返すことができます。
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 バリデーターミドルウェア
Zod バリデーターミドルウェアを使うと、さらに簡単になります。
npm i @hono/zod-validatoryarn add @hono/zod-validatorpnpm add @hono/zod-validatorbun add @hono/zod-validator続いて、zValidator をインポートします。
import { zValidator } from '@hono/zod-validator'次のように記述します。
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 バリデーターミドルウェア
Standard Schema は、TypeScript のバリデーションライブラリーに共通のインターフェースを提供する仕様です。Zod、Valibot、ArkType のメンテナーが作成し、エコシステムのツールがカスタムアダプターなしで任意のバリデーションライブラリーを扱えるようにします。
Standard Schema バリデーターミドルウェアを使うと、Standard Schema に対応する任意のバリデーションライブラリーを Hono で利用できます。一貫した型安全性を保ちながら、好みのバリデーターを柔軟に選べます。
npm i @hono/standard-validatoryarn add @hono/standard-validatorpnpm add @hono/standard-validatorbun add @hono/standard-validatorパッケージから sValidator をインポートします。
import { sValidator } from '@hono/standard-validator'Zod の使用
Standard Schema バリデーターで Zod を使えます。
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}`,
})
})Valibot の使用
Valibot は、モジュール式の設計を採用した Zod の軽量な代替です。
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}`,
})
})ArkType の使用
ArkType は、ランタイムバリデーションに TypeScript に即した構文を提供します。
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}`,
})
})