从零实现 JSON Schema 验证器 - 第三周

发布: (2026年2月7日 GMT+8 00:15)
4 min read
原文: Dev.to

Source: Dev.to

每周更新 – 基础与架构

这周我相当忙,没太多时间做事,但我做出了一些基础性的决定,并遇到了一些小问题。

TypeScript 学习曲线

这是我第一次使用 TypeScript。我原以为它只是“带有静态类型的 JavaScript”,但很快发现我还需要 预先确定对象的静态结构。编写项目的基础部分变得很繁琐,因为每个变量在我定义类型之前都会出现红色波浪线。

虽然这种前期工作让人感到烦恼,但我现在看到它会在后期提升开发体验。

早期挑战

启动一个新项目总是很困难:

  • 没有现有代码可以依附或扩展。
  • 系统的宏观愿景可能让人望而生畏。
  • 你不断在高层架构视角和低层实现视角之间切换。
  • 早期决策会产生长期影响,使后续修改变得困难。

在有点迷茫之后,我通过进一步研究(见下一节)找到了思路。

架构决策

在阅读 JSON Schema 规范之前,维护者建议我 先关注系统的架构,这样以后添加对新 JSON Schema 草案的支持会更直接。

关键字处理对象

我决定创建 关键字处理对象,将关键字名称映射到实现这些关键字的函数。每个支持的草案都有自己的处理对象。

在实现 draft 2020‑12 处理器时,我遇到了阻碍:我不确定处理函数应如何与系统的其余部分集成。研究后发现两种常见的验证器架构:

  1. 递归架构
  2. 访问者架构

访问者架构为我的方法提供了缺失的环节,于是我采用了它。

基于访问者的验证器架构

两种架构都是递归的,但递归的应用方式不同。

  1. 公共入口点validate
    向用户公开的函数。

  2. 模式遍历validateSchema
    控制流程,决定遍历模式的哪一部分,并从关键字处理对象中获取相应的处理器。

  3. 处理器签名

    (schema: any, instance: any, context: ValidationContext) => void
    • schema – 当前子模式。
    • instance – 正在验证的数据。
    • context – 跟踪错误、实例和模式位置、已评估的项/属性,并可能提供实用函数。
  4. 递归委托
    处理器完成工作后,会在任何子模式上调用 validateSchema,将控制权交回遍历逻辑。

  5. 完成
    步骤 2‑4 循环执行,直至验证结束。随后 validate 函数使用累积的 ValidationContext 生成最终的验证结果。

这种设计将 流程控制关键字实现 明确分离,便于添加、更新或移除关键字。

实现说明

  • 我一直在使用大语言模型(LLM)协助实现,但仓库中的每一段代码要么由我亲自编写,要么经过彻底审查。
  • 源代码已在 GitHub 上公开:(replace with the actual URL)。

第 3 周更新结束。

Back to Blog

相关文章

阅读更多 »