使用 Kaapi 构建现代后端:请求验证 第2部分

发布: (2026年1月12日 GMT+8 03:33)
5 min read
原文: Dev.to

Source: Dev.to

本系列面向热爱 TypeScript 并欣赏 Hapi 设计哲学的后端开发者。

再次验证…?

也许你已经跟随了关于请求验证的上一篇文章,使用了 JoiArkTypeValibotZod

你已经拥有了一个光鲜的 Kaapi 应用,路由整洁,验证可靠。一切看起来都很简洁且令人放心。

你可能是从下面这样的代码开始的:

import { z } from 'zod';

app
  .base()
  .zod({
    params: z.object({
      name: z.string().min(3).max(10)
    })
  })
  .route({
    method: 'GET',
    path: '/hello/{name}',
    handler: function (request, h) {
      return `Hello ${request.params.name}!`;
    }
  });

说实话?
这完全可以正常工作。

直到有一天,你的应用不再

某个时刻,路由开始增多。你不再在同一个文件里内联定义它们,而是把它们放在各自的文件中,按功能分组。于是,那条曾经很好用的链子已经不再适用。

于是问题出现了:

当路由不再靠近你的应用时,如何让验证仍然紧贴在路由旁边?

这正是我们在这里要解决的。

新的设置(你可能已经做过了)

你想要两件事:

  1. 独立定义路由 – 在一个地方使用 app.route(...) 注册它们。
  2. 验证、类型安全,并且可以自由选择你喜欢的验证器

让我们一次一个验证器地逐步讲解。

Joi:熟悉的路径

如果你正在使用 Joi,则没有任何变化。这是有意为之。

npm i joi
import { Kaapi, KaapiServerRoute } from '@kaapi/kaapi';
import Joi from 'joi';

const app = new Kaapi({ /* ... */ });

const route: KaapiServerRoute = {
  method: 'GET',
  path: '/hello/{name}',
  options: {
    validate: {
      params: Joi.object({
        name: Joi.string().min(3).max(10).required()
      })
    }
  },
  handler: function (request, h) {
    return `Hello ${request.params.name}!`;
  }
};

app.route(route);

没有魔法。没有惊喜。
如果你以前使用过 Hapi,这应该会让你有回家的感觉。

Zod:与 TypeScript 对话的验证

现在假设你想要 强类型推断,但又不想在泛型之间来回切换。

npm i zod @kaapi/validator-zod

扩展 Kaapi

import { Kaapi } from '@kaapi/kaapi';
import { validatorZod } from '@kaapi/validator-zod';

const app = new Kaapi({ /* ... */ });

await app.extend(validatorZod);

定义路由

import { withSchema } from '@kaapi/validator-zod';
import { z } from 'zod';

const route = withSchema({
  params: z.object({
    name: z.string().min(3).max(10)
  })
}).route({
  method: 'GET',
  path: '/hello/{name}',
  handler: function (request, h) {
    return `Hello ${request.params.name}!`;
  }
});

app.route(route);

没有泛型。你的类型直接来自于 schema。你只需编写一次验证,TypeScript 就会自动跟随。

Valibot:相同思路,不同风格

Valibot 与 Zod 同属一类,只是语法略有不同。

npm i valibot @kaapi/validator-valibot

扩展 Kaapi

import { Kaapi } from '@kaapi/kaapi';
import { validatorValibot } from '@kaapi/validator-valibot';

const app = new Kaapi({ /* ... */ });

await app.extend(validatorValibot);

定义路由

import { withSchema } from '@kaapi/validator-valibot';
import * as v from 'valibot';

const route = withSchema({
  params: v.object({
    name: v.pipe(v.string(), v.minLength(3), v.maxLength(10))
  })
}).route({
  method: 'GET',
  path: '/hello/{name}',
  handler: function (request, h) {
    return `Hello ${request.params.name}!`;
  }
});

app.route(route);

ArkType:您可以阅读的模式

npm i arktype @kaapi/validator-arktype

扩展 Kaapi

import { Kaapi } from '@kaapi/kaapi';
import { validatorArk } from '@kaapi/validator-arktype';

const app = new Kaapi({ /* ... */ });

await app.extend(validatorArk);

定义路由

import { withSchema } from '@kaapi/validator-arktype';
import { type } from 'arktype';

const route = withSchema({
  params: type({
    name: '3 <= string <= 10'
  })
}).route({
  method: 'GET',
  path: '/hello/{name}',
  handler: function (request, h) {
    return `Hello ${request.params.name}!`;
  }
});

app.route(route);

实际重要的内容

不论使用哪种验证器:

  • 路由是独立定义的。
  • 每个路由自行选择所需的验证器。
  • 注册保持极其简单:
app.route(route);
  • Joi 开箱即用。
  • Zod、Valibot 和 ArkType 通过 withSchema 插入。

相同的应用。相同的 API。不同的工具。

那么… 应该使用哪个验证器?

目标推荐的验证器
最小代码量Joi or ArkType
无需泛型的强类型推断Zod or Valibot
易读的模式ArkType
优秀的自动文档Zod, Valibot, or Joi

Kaapi 并不强迫你做出选择。
它为你提供了完整的工具箱。挑选你喜欢使用的螺丝刀吧。

Source code

想要完整示例吗?

👉 github.com/kaapi/kaapi‑examples

shygyver/kaapi-monorepo-playground

示例位于 validation-app 目录下。

查看 README 获取运行说明。

更多 Kaapi 文章即将发布。

本文仅讨论将验证保持在其应有的位置。

📦 立即开始

npm install @kaapi/kaapi

🔗 了解更多: Kaapi Wiki

Back to Blog

相关文章

阅读更多 »

我的 Node.js API 最佳实践 2025年

Node.js 已经为生产环境的 API 提供动力超过十年了,在 2025 年,它已经不再是“新”或实验性的,而是基础设施。正是这种成熟度使得 c...