惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Martin Fowler
Martin Fowler
Y
Y Combinator Blog
M
MIT News - Artificial intelligence
The Cloudflare Blog
WordPress大学
WordPress大学
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园 - 司徒正美
小众软件
小众软件
Blog — PlanetScale
Blog — PlanetScale
雷峰网
雷峰网
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
J
Java Code Geeks
云风的 BLOG
云风的 BLOG
C
Check Point Blog
D
DataBreaches.Net
T
The Blog of Author Tim Ferriss
V
V2EX
F
Fortinet All Blogs
B
Blog
大猫的无限游戏
大猫的无限游戏
N
Netflix TechBlog - Medium
B
Blog RSS Feed
A
About on SuperTechFans
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Implementing a JSON Schema Validator from Scratch - Week 9
Ahmed Hany G · 2026-04-25 · via DEV Community

This was a pretty interesting week, it was more about what I didn't do rather than what I did do.

What I Did

I started this week with the goal of implementing the reference keywords, more specifically $id and $anchor.
Unlike most of the keywords I've worked on lately, this required some serious foundational changes.

Schema Registration

In order to reference schemas, the schemas need to be saved somewhere, so a schema registry was added, as well as a couple of functions for interacting with that schema registry (registerSchema, unregisterSchema, etc.).

Schema Compilation

Keywords like $id and $anchor don't work during the evaluation process, but rather they're supposed to work before the evaluation process ever starts, as a result, a schema compilation process (also known as schema loading and schema pre-processing) is introduced, where the schema is traversed, keywords like $id and $anchor are searched for, and the schema registry is updated based on their values.

This schema compilation process is done each time a new schema is registered.

New Dependency

Implementing $id and $anchor require some URI operations that must follow RFC 3986, so instead of implementing it by hand, I just used the @hyperjump/uri library, which saved me a lot of time, energy, and potential bugs.

What I Didn't Do

At the beginning of this week, I attempted to write my code in a highly maintainable and extendable way, since architecture has been a key focus since the very beginning, but after some struggling, I decided it's better to not do that here.

What I Tried To Do

I tried to write the system in a way where each draft not only has its keyword handlers and phases, but also its compilation keywords and their handlers.
So draft 2020-12 for example would have two keywords here, with $id and $anchor as the keyword names, and their actual implementation mapped to those names.

Whichever draft is being used would have its personal keyword names and implementations for its compilation keywords, since each draft is different, both in keyword name (earlier drafts had id while newer drafts have $id) and behavior (there are subtle behavioral differences between the id/$id keywords in each draft).

The Problem

Implementing this in a decoupled way is surprisingly complex, since unlike the validation keywords, compilation keywords update the state of the schema registry, which is a part of the Validator object, so I'd need to pass to the handler function everything needed to do the required processing and also update the schema registry.

Also, different keywords update the state in different ways. So for example, $anchor just adds new entries to the schema registry, while $id adds to the schema registry, but also affects the behavior of any $anchor or $id that follows it (as its value is used to resolve relative URIs).
And since keyword handlers have separate functions, there would have to be a shared state/variable between them so that keywords like $id and $anchor can work correctly.

Another issue is that different drafts have different names for keywords, so I can't just say to the function that traverses the schema "look for a keyword named $id and use the draft's handler for that keyword", since it's called id in earlier drafts, so I'd also need the draft to know which keyword is responsible for schema identification.

To put it simply, compilation keywords are stateful and order-dependent, which increases the difficulty and complexity of abstraction.

My Rationale

Even if I can do all that, I don't believe it's worth the trouble.
It adds too much complexity for something that I just won't need. Extensibility and adding drafts easily was an important goal from the start of this project, but I feel like this is just too much effort fixing a problem that I'll never really deal with.

So in the end, I chose to just couple the compilation process with the Validator object, if I do find myself facing problems in the future because of this, I'll just fix it then, but I doubt that'll happen.

Conclusion

Not a lot of code was written this week, but I've learned a lot, and I've gained more experience in avoiding "tunnel vision" and trying too hard to fix problems that should just be ignored (which is a problem that I've faced a lot over the years).
I'm quite satisfied with this outcome.

As always, the code can be found on GitHub