跳转到正文

校验 ​

Hono 只提供一个非常轻量的校验器。 不过,与第三方校验器结合使用时,它可以发挥强大的作用。 此外,RPC 功能允许你通过类型与客户端共享 API 规范。

手动校验器 ​

首先介绍无需第三方校验器即可校验传入值的方法。

从 hono/validator 中导入 validator。

ts
import { validator } from 'hono/validator'

要校验表单数据,请将 form 作为第一个参数,回调函数作为第二个参数。 在回调中校验值,并在最后返回通过校验的值。 validator 可以作为中间件使用。

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,
    }
  }),
  //...

在处理函数中,可以使用 c.req.valid('form') 获取通过校验的值。

ts
, (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()。

假设有如下应用。

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)
  }
)

可以这样编写测试。

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' }

注意

校验 header 时,必须使用小写名称作为键。

如果想校验 Idempotency-Key 标头,需要使用 idempotency-key 作为键。

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')
    // ...
  }
)

多个校验器 ​

也可以使用多个校验器,分别校验请求的不同部分:

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

使用 Zod ​

可以使用第三方校验器之一 Zod。 我们推荐使用第三方校验器。

从 npm 注册表安装。

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

从 zod 中导入 z。

ts
import * as z from 'zod'

编写 schema。

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

可以在回调函数中使用 schema 进行校验,并返回通过校验的值。

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
    )
  }
)

Zod 校验器中间件 ​

使用 Zod 校验器中间件会更加简单。

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

然后导入 zValidator。

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

按以下方式编写。

ts
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 校验器中间件允许你在 Hono 中使用任何兼容 Standard Schema 的校验库,在保持一致类型安全性的同时,灵活选择你偏好的校验器。

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

从软件包中导入 sValidator:

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

使用 Zod ​

可以将 Zod 与 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}`,
  })
})

使用 Valibot ​

Valibot 是 Zod 的轻量替代方案,采用模块化设计:

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}`,
  })
})

使用 ArkType ​

ArkType 为运行时校验提供 TypeScript 原生风格的语法:

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}`,
  })
})

基于 MIT 许可证发布。