Unkey 共享验证包 @unkey/validation 解析:用户自定义标识符的 Schema 约束与实现原理
Unkey 共享验证包 unkey/validation 解析用户自定义标识符的 Schema 约束与实现原理【免费下载链接】unkeyThe Developer Platform for Modern APIs项目地址: https://gitcode.com/GitHub_Trending/un/unkey本篇文章以 Unkey 仓库中 web/internal/validation/README.md 为骨架深入剖析unkey/validation这一共享验证包的设计意图、四个核心 Zod Schema 的约束规则以及它们如何在 URL 安全、数据库存储与业务语义之间取得平衡。读完本文你将掌握 Unkey 对用户自定义标识符user-chosen identifier与人读名称human-readable name两类字段的验证口径并能直接复用这套 Schema 约束到自己的 API 与前端表单校验中。包定位一段话读懂 unkey/validationunkey/validation的定位非常聚焦README 中的原文只有一句核心描述unkey/validationcontains various shared schema or validation utils. For example user-chosen identifiers.即它是一个在 Unkey 多个应用之间共享的 Schema / 验证工具集合典型场景是校验用户自行选择的标识符identifier。在 Unkey 的产品语境里这类标识符会被用作查找键lookup key——例如自定义命名空间名、App 的 slug、Permission 的名称等它们会出现在 URL、API 请求体与数据库索引列中因此必须同时满足URL 安全与数据库列类型约束两个硬性前提。从包结构看它被设计成一个独立的 workspace 包包入口与唯一实现位于 src/index.ts包的元信息见 package.json名称为unkey/validation版本 1.0.0仅依赖zod通过 pnpm workspace 的catalog:统一管理版本devDependencies 使用typescript5.5.3 与 workspace 内的unkey/tsconfig该包已被仪表盘应用通过workspace:^方式引用见 web/apps/dashboard/package.json 中的unkey/validation: workspace:^说明它在 Web 前端侧是实际被消费的共享依赖。四个核心 Schema字段语义与约束规则逐条拆解src/index.ts 中导出了一个名为validation的对象聚合了四个 Zod Schemaidentifier、name、description、unkeyId。下面逐条拆解其约束与设计动机。identifierURL 安全的查找键const identifier z .string() .min(3) .max(256) .regex( /^[a-zA-Z0-9_\.:\-]*$/, Only alphanumeric, underscores, periods, colons and hyphens are allowed, );源码注释明确了它的语义src/index.ts 第 3-6 行An identifier is any string the user gives us to be used as a lookup key. It must be URL safe and fit into our database (varchar 256).min(3) / max(256)长度下限 3、上限 256。256 的上限与数据库varchar(256)列定义严格对应从源头杜绝超长输入导致的数据截断或写入失败。字符白名单正则^[a-zA-Z0-9_\.:\-]*$只允许字母大小写、数字、下划线_、句点.、冒号:与连字符-。这些字符在 URL 路径与查询串中都是安全的无需额外转义即可嵌入链接。一个值得注意的实现细节正则量词用的是*允许零个字符而不是理论上单独看正则可以匹配空串但 Zod 会先执行min(3)的长度校验因此最终通过校验的字符串必然满足长度 ≥ 3 且全部命中字符白名单。这种长度约束 字符约束的组合写法将两个关注点拆开更易阅读与维护。错误信息也直接面向开发者Only alphanumeric, underscores, periods, colons and hyphens are allowed当非法字符出现时Zod 会将该消息作为校验失败的 message 返回。name给人看的可读名称const name z.string().min(3).max(256);语义源码注释A name is a user given human-readable string. It must not be used in URLs.——例如某个 Key 的名称。规则上不限制字符集只约束长度 3256因为名称仅用于展示与检索语义不会拼进 URL。它与identifier形成鲜明对照进 URL 的字段严格限制字符集不进 URL 的字段放开字符集。这是本包最具代表性的分层设计思想。description可选的自由文本const description z .string() .min(3) .max(256) .optional() .or(z.literal());语义源码注释A description is a user given human-readable string. It must not be used in URLs.——例如某个 Permission 的描述。长度同样限制为 3256但通过.optional()允许整个字段缺省同时用.or(z.literal())额外放行空字符串。因此该字段的合法取值集合为未提供 / 空字符串 / 长度在 3256 的任意字符串。注意空字符串与长度为 12 的非空字符串都被拒绝避免出现无意义的单字符描述。unkeyId带前缀的 Unkey 资源 IDconst unkeyId z .string() .regex( /^[a-z]{3,4}_[a-zA-Z0-9]{8,}$/, Unkey IDs must include a prefix, separated by an underscore: key_abcdefg123, );正则^[a-z]{3,4}_[a-zA-Z0-9]{8,}$规定 Unkey 资源 ID 必须由三部分组成34 位小写字母前缀 下划线分隔符 至少 8 位字母数字后缀。例如错误信息中给出的key_abcdefg123前缀key表明资源类型下划线后是随机生成的主体部分。该规则与仓库中大量以key_、app_、api_等前缀开头的资源 ID 用法一致例如 cmd/api/apps/delete_app.go 中的 CLI 示例--appapp_1234abcd正是这种前缀 下划线 主体命名的直接体现。该 Schema 没有显式的max长度下限由至少 8 位后缀隐式保证最短为 31812 个字符这是与identifier不同的策略——资源 ID 由系统生成而非用户输入因此只需约束形态无需约束长度上限。导出方式与消费形态源码末尾将四个 Schema 聚合为一个命名导出对象src/index.ts 第 41-45 行export const validation { identifier, name, description, unkeyId, };消费方可以按需解构使用例如import { validation } from unkey/validation; // 校验用户自定义标识符 const result validation.identifier.safeParse(my-namespace_1); // 校验 Unkey 资源 ID const id validation.unkeyId.parse(key_abcdefg123);由于底层基于 ZodsafeParse/parse/refine等标准能力全部可用可以无缝嵌入 React Hook Form、tRPC、API 层入参校验等任何 Zod 生态场景。包通过main与types字段直接指向src/index.tspackage.json即源码即产物配合 TypeScript 工作区直接消费。与后端 slug 语义的呼应从验证到业务identifier的URL 安全 唯一查找键语义在 Unkey 后端 CLI 的 App slug 设计中可以得到印证。在 cmd/api/apps/create_app.go 中可以看到The slug you provide is the stable, caller-defined handle used to reference this app. It must be unique within the project.对应的 CLI 用法为unkey api apps create-app --projectpayments --namePayments API --slugpayments-apicreate_app_test.go 中亦有同名测试用例。这里--name人读名称可含空格与--slugURL 安全标识符的分工与前文name/identifier两个 Schema 的语义完全一致说明unkey/validation中的约束不是孤立的表单校验而是贯穿前端输入 → API 请求 → 数据库存储全链路的统一口径。如何在本仓库中继续深入想查看包的完整实现与注释直接阅读 src/index.ts想了解包被谁依赖可检索 web/apps/dashboard/package.json 与 web/pnpm-lock.yaml想对比用户标识符在后端业务中的实际用法可阅读 cmd/api/apps/create_app.go 及其测试 create_app_test.go。小结unkey/validation用约 45 行代码回答了一个关键问题用户输入如何被安全地转化为可查找、可存储、可入 URL 的键。identifier负责 URL 安全的查找键name/description负责不限制字符的人类可读文本unkeyId负责系统生成资源 ID 的形态约束。这套分层口径——进 URL 的收紧字符集、不进 URL 的放开字符集、系统生成的只约束形态——是 Unkey 在多应用共享验证逻辑时的核心经验直接复用这四个 Schema 或借鉴其拆分思路都能显著降低前后端校验口径漂移的风险。【免费下载链接】unkeyThe Developer Platform for Modern APIs项目地址: https://gitcode.com/GitHub_Trending/un/unkey创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考