<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ahmed Hany Gamal</title>
    <description>The latest articles on Forem by Ahmed Hany Gamal (@ahmedhanygamal).</description>
    <link>https://forem.com/ahmedhanygamal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3715055%2F24d52963-dcc7-434c-9c8b-ba554acb449f.jpeg</url>
      <title>Forem: Ahmed Hany Gamal</title>
      <link>https://forem.com/ahmedhanygamal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ahmedhanygamal"/>
    <language>en</language>
    <item>
      <title>Implementing a JSON Schema Validator from Scratch - Week 7</title>
      <dc:creator>Ahmed Hany Gamal</dc:creator>
      <pubDate>Fri, 06 Mar 2026 13:17:38 +0000</pubDate>
      <link>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-7-33pj</link>
      <guid>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-7-33pj</guid>
      <description>&lt;p&gt;As I stated last time, this was a pretty short week.&lt;/p&gt;

&lt;p&gt;I only added one thing to the validator, which is evaluation phases.&lt;/p&gt;

&lt;p&gt;The idea is simple, not all keywords are created equal, some need to be processed earlier (like &lt;code&gt;$schema&lt;/code&gt; and &lt;code&gt;$id&lt;/code&gt;), while some need to be processed later (like the unevaluated keywords). So I've introduced evaluation phases to support this behavior.&lt;/p&gt;

&lt;p&gt;Each draft object now has a &lt;code&gt;PHASE_ORDER&lt;/code&gt; property, which is an array of phases (where a phase is just an enum string), each keyword has a specific phase assigned to it, the &lt;code&gt;ValidationContext.evaluate&lt;/code&gt; function doesn't just go through all the entries of the schema object in their written order anymore, but rather, it goes through them based on the phases in the &lt;code&gt;PHASE_ORDER&lt;/code&gt; array, allowing for different keywords to be evaluated in different phases.&lt;/p&gt;

&lt;p&gt;The code can be found on &lt;a href="https://github.com/AhmedHanyGamal/json-schema-validator" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jsonschema</category>
      <category>showdev</category>
      <category>typescript</category>
      <category>learning</category>
    </item>
    <item>
      <title>Implementing a JSON Schema Validator from Scratch - Week 6</title>
      <dc:creator>Ahmed Hany Gamal</dc:creator>
      <pubDate>Fri, 27 Feb 2026 15:38:32 +0000</pubDate>
      <link>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-6-k2e</link>
      <guid>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-6-k2e</guid>
      <description>&lt;p&gt;This was a good week&lt;br&gt;
I implemented three new keywords, those being &lt;code&gt;allOf&lt;/code&gt;, &lt;code&gt;anyOf&lt;/code&gt;, and &lt;code&gt;oneOf&lt;/code&gt;, and I changed the system's foundation for the really real final last time :^)&lt;br&gt;
Let's get into the specifics&lt;/p&gt;
&lt;h2&gt;
  
  
  The System's Foundation
&lt;/h2&gt;

&lt;p&gt;After I initially implemented the &lt;code&gt;allOf&lt;/code&gt;, &lt;code&gt;anyOf&lt;/code&gt;, and &lt;code&gt;oneOf&lt;/code&gt; keywords, I started to visualize how I'd implement the unevaluated keywords (&lt;code&gt;unevaluatedProperties&lt;/code&gt; and &lt;code&gt;unevaluatedItems&lt;/code&gt;), so I started thinking, then I started doing some research, and then I realized something important, my understanding of the expected behavior of the unevaluated keywords was wrong.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Unevaluated Keywords
&lt;/h3&gt;

&lt;p&gt;I thought the unevaluated keywords caught all the properties/items that hadn't been evaluated in the same schema that the unevaluated keyword was being used in, as well as every sub-schema inside it.&lt;br&gt;
The first half of this paragraph is correct, the second half is not.&lt;/p&gt;

&lt;p&gt;The unevaluated keywords track the properties/items evaluated in the same schema as them, as well as the properties/items evaluated in the applicators adjacent to them, but that's it.&lt;/p&gt;

&lt;p&gt;I know this might seem unclear, so let me give you a few examples for illustration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"unevaluatedProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an incredibly basic example, the allowed instances would either be an object with a property called &lt;code&gt;foo&lt;/code&gt; of type string (so something like &lt;code&gt;{"foo": "this is a string"}&lt;/code&gt;) or an empty object (&lt;code&gt;{}&lt;/code&gt;).&lt;br&gt;
Here the &lt;code&gt;unevaluatedProperties&lt;/code&gt; keyword is interchangeable with the &lt;code&gt;additionalProperties&lt;/code&gt; keyword.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"allOf"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"unevaluatedProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example shows the difference between the unevaluated keywords and something like &lt;code&gt;additionalProperties&lt;/code&gt;, as well as the reason the unevaluated keywords exist.&lt;br&gt;
This example is identical to the previous one, but the same can't be said if &lt;code&gt;additionalProperties&lt;/code&gt; was used instead of &lt;code&gt;unevaluatedProperties&lt;/code&gt;, as the only allowed instance would then be an empty object (&lt;code&gt;{}&lt;/code&gt;), since &lt;code&gt;additionalProperties&lt;/code&gt; only sees/tracks the properties from property keywords like &lt;code&gt;properties&lt;/code&gt; and &lt;code&gt;patternProperties&lt;/code&gt; and does not see or track anything inside any other type of applicator keyword&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integer"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"unevaluatedProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the case where I misunderstood things. I thought the unevaluated keywords would track all of the keywords inside all of the sub-schemas inside the schema containing the unevaluated keyword, if that were the case, the only possible instance values would have been &lt;code&gt;{}&lt;/code&gt;, &lt;code&gt;{ "foo": {} }&lt;/code&gt;, and &lt;code&gt;"foo": { "bar": 123 }&lt;/code&gt; (or any other integer), but that's not the case, since the unevaluated keywords only check its adjacent applicator keywords.&lt;br&gt;
As a result, the schema forbids the use of any property at the root level with a name other than "foo", and this "foo" property has to be an object, but the unevaluated keyword does not track whatever is inside that inner object inside the "foo" property, so &lt;code&gt;{ "foo": { "baz": "untracked prop" } }&lt;/code&gt; would be a valid instance.&lt;/p&gt;

&lt;p&gt;I'll talk more about how this affected the code in the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;

&lt;p&gt;These are the additions and changes done to the code base last week&lt;/p&gt;

&lt;h3&gt;
  
  
  Evaluation Tracking
&lt;/h3&gt;

&lt;p&gt;In order to support the unevaluated keywords later, some changes needed to be done in the system's foundation, primarily, the addition of &lt;code&gt;evaluatedProperties&lt;/code&gt; and &lt;code&gt;evaluatedItems&lt;/code&gt; to the &lt;code&gt;BasicPendingUnit&lt;/code&gt; interface, and the creation of the &lt;code&gt;EvaluationResult&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;BasicPendingUnit&lt;/code&gt; now has two additional mandatory properties, those being &lt;code&gt;evaluatedProperties&lt;/code&gt; and &lt;code&gt;evaluatedItems&lt;/code&gt;, which are used to track the evaluated properties and evaluated items respectively. So now keywords are not only responsible for updating the annotations in the &lt;code&gt;BasicPendingUnit&lt;/code&gt;, but also the evaluation properties, which I expect could result in hidden bugs in the future as I forget to add some elements to the evaluated list in some random keyword, but this is the cleanest idea that came to my mind.&lt;/p&gt;

&lt;p&gt;Also, the &lt;code&gt;ValidationContext.evaluate&lt;/code&gt; method (formerly known as &lt;code&gt;validateHelper&lt;/code&gt;) now returns an &lt;code&gt;EvaluationResult&lt;/code&gt; object, which is an object containing a boolean property called &lt;code&gt;valid&lt;/code&gt; denoting whether or not the evaluation was valid, and a &lt;code&gt;BasicPendingUnit&lt;/code&gt; called &lt;code&gt;unit&lt;/code&gt;, which contains the pending unit after the schema/sub-schema evaluation is done, so that it would contain all of the evaluation details, most importantly the evaluation properties.&lt;br&gt;
The reason for this is that keywords like &lt;code&gt;anyOf&lt;/code&gt; or &lt;code&gt;allOf&lt;/code&gt; would have a copy of all the evaluated properties/items from all their sub-schemas, which they would then be able to use to aggregate them based on the logic of the individual keyword.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keyword Handlers
&lt;/h3&gt;

&lt;p&gt;As mentioned, I've implemented the keyword handlers for the &lt;code&gt;allOf&lt;/code&gt;, &lt;code&gt;anyOf&lt;/code&gt;, and &lt;code&gt;oneOf&lt;/code&gt; keywords.&lt;/p&gt;

&lt;p&gt;Not much can be said here, I saw how they were supposed to behave, and implemented them, but there is one thing that I think might be worth mentioning. &lt;/p&gt;

&lt;p&gt;When working on a keyword, I believe the section of the specs talking about the keyword &lt;strong&gt;MUST&lt;/strong&gt; be read, as even if you understand the behavior of the keyword, a lot of times there are subtle details that you might miss, I'm talking about things like annotation behavior and edge cases.&lt;br&gt;
With all honestly, sometimes I'm just too lazy to read the specs, so I ask notebookLM instead, and since it only has the specs as its resources, I believe its answers are pretty accurate, but even so, I'll probably refrain from doing this, or at least do it less, and there are two reasons for this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;As good as it is, I can't fully trust it. I actually went through the specs while writing this blog post, because I became aware that the specs are the definitive source of truth, and anything else could be wrong&lt;/li&gt;
&lt;li&gt;The main reason I even use things like notebookLM is to save time and energy, but honestly, reading the specs would have probably taken way less time and energy&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The addition of evaluation tracking has added a lot of complexity to the code base, I feel like there are twice as much ways to create hard-to-find bugs now, but other than that, everything is great, I have a pretty solid foundation (that definitely won't see any changes in the future), there aren't really any major architectural changes that I'm expecting, I've implemented a bunch of the more difficult keywords, and I expect most of the remaining work to be fun.&lt;/p&gt;

&lt;p&gt;I'll be dedicating some time over the next couple of weeks to qualification tasks and proposal work for Google Summer of Code, so validator progress will probably be smaller during that period.&lt;/p&gt;

&lt;p&gt;The code can be found on &lt;a href="https://github.com/AhmedHanyGamal/json-schema-validator" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jsonschema</category>
      <category>showdev</category>
      <category>typescript</category>
      <category>learning</category>
    </item>
    <item>
      <title>Implementing a JSON Schema Validator from Scratch - Week 5</title>
      <dc:creator>Ahmed Hany Gamal</dc:creator>
      <pubDate>Fri, 20 Feb 2026 13:22:43 +0000</pubDate>
      <link>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-5-2f59</link>
      <guid>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-5-2f59</guid>
      <description>&lt;p&gt;This was a very insightful week, even though I didn't complete many visible tasks.&lt;/p&gt;

&lt;p&gt;I properly implemented three keywords, though they're very simple ones, those being the &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;required&lt;/code&gt;, and &lt;code&gt;properties&lt;/code&gt; keywords.&lt;br&gt;
Most of this week was spent either building the  system's foundation or refactoring parts of it after realizing that changes were needed for a  more stable system.&lt;/p&gt;

&lt;p&gt;The JSON Schema maintainers weren't joking when they talked about the "'just one more thing and I'll be done!' 100x over" effect.&lt;br&gt;
That being said, I just have one more thing to do, and then I'll be done with the foundation (lol).&lt;/p&gt;

&lt;p&gt;Now into the specifics&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Changed
&lt;/h2&gt;

&lt;p&gt;These are the things that I've updated in the system's foundation.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;validateHelper&lt;/code&gt; Function Signature
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;validateHelper&lt;/code&gt; function (formerly known as the &lt;code&gt;validateSchema&lt;/code&gt; function) will now return a boolean value, representing whether the schema/sub-schema is valid or not.&lt;/p&gt;

&lt;p&gt;This will make a big difference when implementing keywords that deal with multiple sub-schemas (e.g. &lt;code&gt;allOf&lt;/code&gt;, &lt;code&gt;anyOf&lt;/code&gt;, etc.).&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;PendingUnit&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;I've created a new interface called &lt;code&gt;BasicPendingUnit&lt;/code&gt;, which represents an output unit that is still being constructed. Since success and failure units are finalized objects, the pending unit is used during the phase where the keywords are still being processed, before the unit gets finalized at the end.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing The New Output Format
&lt;/h3&gt;

&lt;p&gt;As I mentioned &lt;a href="https://dev.to/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-4-51m3"&gt;last week&lt;/a&gt;, there's a &lt;a href="https://json-schema.org/blog/posts/fixing-json-schema-output" rel="noopener noreferrer"&gt;new output format&lt;/a&gt; that addresses the issues of the original output format from the specs, and it's the one that I'll work with.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;validateHelper&lt;/code&gt; function is going to create a &lt;code&gt;PendingUnit&lt;/code&gt; (more on that later) for each schema/sub-schema, which would then be used by all the keywords to populate the &lt;code&gt;errors&lt;/code&gt; and &lt;code&gt;annotations&lt;/code&gt; properties, which allows for one output unit to exist for each schema/sub-schema with all its relevant data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Location Handling
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;ValidationContext&lt;/code&gt; class no longer tracks the location (&lt;code&gt;evaluationPath&lt;/code&gt;, &lt;code&gt;schemaLocation&lt;/code&gt;, and &lt;code&gt;instanceLocation&lt;/code&gt;), it now only contains the output units. The location is now separately passed to the &lt;code&gt;validateHelper&lt;/code&gt; function (the function that orchestrates the validation process).&lt;/p&gt;

&lt;p&gt;The reason for this design choice is to minimize mutability.&lt;br&gt;
Originally, the &lt;code&gt;ValidationContext&lt;/code&gt; class contained a shared mutable location instance, and that instance would be mutated every time the &lt;code&gt;validateHelper&lt;/code&gt; function was (recursively) called, which required me to undo these changes at the end of every keyword implementation that called the &lt;code&gt;validateHelper&lt;/code&gt; function, which is very error-prone.&lt;/p&gt;

&lt;p&gt;The new design choice allows each &lt;code&gt;validateHelper&lt;/code&gt; function call, and by extension each output unit to contain its own local location instance that it can mutate as much as needed without creating side-effects in other parts of the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Things I Plan on Adding
&lt;/h2&gt;

&lt;p&gt;Here are some of the things that I'm actively working on in the project's foundation&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating The JSON Pointer classes
&lt;/h3&gt;

&lt;p&gt;I think I've implemented these classes pretty well, but the &lt;code&gt;fork&lt;/code&gt; methods have an issue, they can only take one segment as an argument, so keywords like &lt;code&gt;properties&lt;/code&gt; which adds something like "/properties/property_name" into the JSON Pointer would require me to pass a very ugly and error prone argument similar to &lt;code&gt;`/properties/${property_name}`&lt;/code&gt;. So this has to be fixed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integrate Keyword Phases
&lt;/h3&gt;

&lt;p&gt;Not all keywords are created equal, some keywords must be used in the very beginning, some must be used at the very end, and some don't really care. As a result, keywords would be split into different phases, the keywords in the beginning phases would be the first to execute (think of keywords like &lt;code&gt;$schema&lt;/code&gt; and &lt;code&gt;$id&lt;/code&gt;), the keywords in the ending phases would be the last to execute (like the &lt;code&gt;unevaluatedProperties&lt;/code&gt; and &lt;code&gt;unevaluatedItems&lt;/code&gt; keywords), and so on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons From My Implementation
&lt;/h2&gt;

&lt;p&gt;I meant what I said when I said this was an insightful week, but most of this insight was broad and mindset related rather than technical spec stuff&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't Freeze! Code and Correct Later
&lt;/h3&gt;

&lt;p&gt;Imagining the problems that you'll face a month into coding is a very hard task, especially when it's your first time implementing the system, but it's a necessary thing to do when you first start working on the system, but after that's done, you don't need to do that as much.&lt;/p&gt;

&lt;p&gt;Once you have something concrete to work with and build upon, you get the ability to just write code and not worry about the future consequences as much, and that'll allow you to face those consequences first hand, which will let you &lt;strong&gt;see&lt;/strong&gt; the problems, as opposed to &lt;strong&gt;guessing&lt;/strong&gt; or &lt;strong&gt;imagining&lt;/strong&gt; them. That way, you have a clear problem to solve, and don't need to spend a lot of time and effort simulating future problems to solve.&lt;/p&gt;

&lt;p&gt;All that being said, you need to stop and actually solve those problems, otherwise you'd just be sacrificing the system's design and settling for spaghetti.&lt;/p&gt;

&lt;p&gt;The code can be found on &lt;a href="https://github.com/AhmedHanyGamal/json-schema-validator" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jsonschema</category>
      <category>showdev</category>
      <category>typescript</category>
      <category>learning</category>
    </item>
    <item>
      <title>Implementing a JSON Schema Validator from Scratch - Week 4</title>
      <dc:creator>Ahmed Hany Gamal</dc:creator>
      <pubDate>Fri, 13 Feb 2026 21:38:28 +0000</pubDate>
      <link>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-4-51m3</link>
      <guid>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-4-51m3</guid>
      <description>&lt;p&gt;This week was... challenging, but in a good way.&lt;br&gt;
I didn't really implement any keywords (unless you count the makeshift &lt;code&gt;type&lt;/code&gt; implementation from last week), but I did build the majority of the foundation for this project, and even though some parts took way more than what I'd expected, I feel like most of my issues from last week have been fixed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue Resolution
&lt;/h2&gt;

&lt;p&gt;If you want a more detailed explanation of each of the upcoming issues, you can check out &lt;a href="https://dev.to/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-3-1oa9"&gt;last week's blog&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typescript Strictness
&lt;/h3&gt;

&lt;p&gt;This mostly bothered me when I was working on the types for each of the system components, and even though it took a lot of time and effort to finish, it's done now, and it's actually made working on other parts of the system easier, and to be clear, when I say that this part is "done", I don't mean that I will never go near it again, I probably will, but it shouldn't be anything drastic, but rather just minor tweaks.&lt;/p&gt;

&lt;p&gt;The difficulty with this part was to write the types in a way that is both flexible enough for what it's needed for, whilst also being strict enough to actually support the project structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the Foundation
&lt;/h3&gt;

&lt;p&gt;At this point, I've finished most of the project's foundation, giving me something to work with. I'm no longer writing code in an empty file, but rather, I have something solid that I can attach new code to.&lt;/p&gt;

&lt;p&gt;Also, most of the foundational/architectural parts of the code are finished, so I don't need to keep thinking of "how might this make me miserable in the future" as much while writing code, which was pretty exhausting. Most of that exhaustion comes from uncertainty, you reach a point where you're unsure if you're future-proofing your code, or if you're just paranoid.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Did This Week
&lt;/h2&gt;

&lt;p&gt;Most of what I did last week was architecture related, so I didn't really implement any keywords, but I did lay the foundation that would help me implement keywords more efficiently, with less potential bugs, and less difficulty.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON Pointers
&lt;/h3&gt;

&lt;p&gt;Initially, I planned on just using an npm package for JSON Pointers, but most of the packages that I found had JSON Pointer classes with much more features and details than what I needed. I just wanted a class to track JSON Pointers, no need for JSON construction, JSON navigation, and all of these things that I found in the &lt;code&gt;json-pointer&lt;/code&gt;, &lt;code&gt;jsonpointer&lt;/code&gt;, and &lt;code&gt;@hyperjump/json-pointer&lt;/code&gt;  packages. So, I decided to just implement it myself.&lt;/p&gt;

&lt;p&gt;This class took way more time than expected, it took over a full day of work just to finish the base class (which I spent even more time adding some extra methods to, but more on that in a bit).&lt;/p&gt;

&lt;p&gt;One of the reasons this took more time than expected was the fact that it turned out I didn't fully understand JSON Pointers. &lt;br&gt;
I understood how to escape and unescape, how a JSON Pointer worked, how it navigated a schema/instance, but I was a bit confused with the purpose of escaping and unescaping. &lt;br&gt;
Initially, I escaped any input to the JSON Pointer object, and unescaped any output from it, but then I realized that it was the other way around, and then I realized that I shouldn't do that for every single input/output method, but rather just the ones that deal with JSON Pointer strings. &lt;br&gt;
The reason for this is because the purpose of escaping and unescaping is to deal with string representations of JSON Pointers, and string representations are expected to use &lt;code&gt;~0&lt;/code&gt; and &lt;code&gt;~1&lt;/code&gt; to represent &lt;code&gt;~&lt;/code&gt; and &lt;code&gt;/&lt;/code&gt; respectively, so you unescape to do that conversion when creating a JSON Pointer object using a JSON Pointer string so that the object can structure the JSON Pointer correctly, and you escape when you output the string representation of that JSON Pointer object so that you have a correctly formatted JSON Pointer string, and you only ever escape and unescape when dealing with JSON Pointer strings, so if you directly &lt;code&gt;push&lt;/code&gt; or &lt;code&gt;pop&lt;/code&gt; a segment, you shouldn't escape or unescape.&lt;/p&gt;

&lt;p&gt;Also, after I fully understood how JSON Pointers worked and finished working on the classes, I realized that I need to add some extra methods (the &lt;code&gt;fork&lt;/code&gt; and &lt;code&gt;reconstruct&lt;/code&gt; methods), since those methods would make the rest of my code easier to write and decrease the likelihood of me adding bugs that would potentially take days of debugging to fix (e.g. having a hidden bug because I forgot to &lt;code&gt;pop&lt;/code&gt; a segment at the end of a random recursive run in a random keyword implementation).&lt;/p&gt;

&lt;p&gt;Even though this took way more time than I expected, it actually deepened my understanding of how JSON Pointers work and gave me a clear mental model of what I need to think of and do when working on foundational parts of a system, and that's the main purpose of this project, learning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Output Format
&lt;/h3&gt;

&lt;p&gt;This is an interesting one.&lt;br&gt;
After reading the specs and trying to implement the logic and structure for the Output result, I was unable to actually work on it, since some parts were unclear in the specs, so I asked the JSON Schema maintainers on slack, and I was given a &lt;a href="https://json-schema.org/blog/posts/fixing-json-schema-output" rel="noopener noreferrer"&gt;blog post&lt;/a&gt; by Greg Dennis, who is one of the maintainers at JSON Schema, and the main person who worked on the &lt;a href="https://json-schema.org/draft/2020-12/json-schema-core#name-output-formatting" rel="noopener noreferrer"&gt;Output Formatting&lt;/a&gt; section in the specs. &lt;br&gt;
In that blog post, he said that there were problems with how Output results were structured, and that he had made an updated version of it that fixes those problems.&lt;/p&gt;

&lt;p&gt;The new Output Format is just amazing, it's just super simple, clear, and pragmatic. I'd advise anyone interested in JSON Schema to take a look at it.&lt;/p&gt;

&lt;p&gt;Also, after some back and forth with one of the maintainers, I decided to ditch the detailed output format in favor of the basic one. The detailed output format probably wouldn't be that hard to do, but the basic one is just trivial, and it's better to save as much time and energy as I can, since I still have a lot of things to do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visitor Architecture
&lt;/h3&gt;

&lt;p&gt;I explained how the Visitor Architecture worked in &lt;a href="https://dev.to/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-3-1oa9"&gt;last week's blog&lt;/a&gt;, so I won't re-explain it here, but I will talk about what I did and what I plan on doing.&lt;/p&gt;

&lt;p&gt;The Visitor Architecture has 2 primary components that interact with one another, those being the &lt;code&gt;ValidationContext&lt;/code&gt; and the individual keyword implementations.&lt;/p&gt;

&lt;p&gt;The plan is to keep the individual keyword implementations "dumb" and give the &lt;code&gt;ValidationContext&lt;/code&gt; pretty much all of the power. The reason for this is separation of concerns, so that I'm less likely to mess up when working on the keyword implementations (e.g. making a mistake when trying to save an error object in one of the keyword implementations, so the code for saving error objects would be in a method inside &lt;code&gt;ValidationContext&lt;/code&gt; and saving errors in keyword implementations would only be done using that method).&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ValidationContext&lt;/code&gt; is the last part of this project's foundation that still needs a good amount of work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Thoughts
&lt;/h2&gt;

&lt;p&gt;These are some things that are on my mind relating to upcoming tasks in this project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;I'm definitely planning on using the official JSON Schema Test Suite for this project, no use having a bunch of code if it doesn't actually do what it's supposed to, and I can't be sure it does unless I test it.&lt;br&gt;
But I'm planning on doing this when I actually have something tangible to test, so I'll probably wait until I finish implementing a couple of good keywords before I start testing my code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;When I started writing the code for this project, I was seriously overwhelmed, mostly because I just felt completely lost, but right now, that feeling is completely gone.&lt;br&gt;
If I had to guess, I'd say things are only going to get more exciting from now on.&lt;/p&gt;

&lt;p&gt;The code can be found on &lt;a href="https://github.com/AhmedHanyGamal/json-schema-validator" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jsonschema</category>
      <category>learning</category>
      <category>typescript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Implementing a JSON Schema Validator from Scratch - Week 3</title>
      <dc:creator>Ahmed Hany Gamal</dc:creator>
      <pubDate>Fri, 06 Feb 2026 16:15:23 +0000</pubDate>
      <link>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-3-1oa9</link>
      <guid>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-3-1oa9</guid>
      <description>&lt;p&gt;I was pretty busy this week, so I didn't have time to do much, but I did make some foundational decisions and faced some minor issues which I'll talk about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Difficulties I Faced
&lt;/h2&gt;

&lt;p&gt;The issues I faced weren't that big, but they were pretty annoying in the moment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typescript Strictness
&lt;/h3&gt;

&lt;p&gt;This is my first time using Typescript, and going into it, I expected it to be pretty simple, just Javascript with static types, but I was surprised that I needed to predetermine the static structure of the objects as well, as opposed to just saying defining the variable as an object and treating that object the same as in Javascript.&lt;/p&gt;

&lt;p&gt;This was pretty annoying since I was trying to write the foundational part of my project, and that's pretty hard to do when every variable you write has red squiggly lines under it, which forces you to spend time and energy on writing the types for each variable, all that while you're in the middle of writing the project's foundation.&lt;/p&gt;

&lt;p&gt;But apart from that, I actually think this would make the development experience more enjoyable later on, I was just surprised with how I had to pay time and effort for the types upfront.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building The Foundation
&lt;/h3&gt;

&lt;p&gt;As with any project, the beginning is relatively hard compared to the rest, because&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;There's nothing to attach your code to or extend, it's just an empty file, and it's hard to determine where to start and how&lt;/li&gt;
&lt;li&gt;It's pretty daunting, since you have a broad image of how this system should look like, and all of the things that you need to do, which makes the project look very intimidating&lt;/li&gt;
&lt;li&gt;You need to constantly shift your perspective between the broad view of the architect and the narrow view of the implementer. Later on, most of the architectural decisions are already made, so you just view things as an implementer&lt;/li&gt;
&lt;li&gt;Your decisions now will have consequences later, and changing them then would be incredibly difficult&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;but after being a bit lost at the beginning, everything just clicked when I did some more research (I'll talk about this in detail in the next section).&lt;/p&gt;

&lt;h2&gt;
  
  
  Foundational Decisions
&lt;/h2&gt;

&lt;p&gt;From very early on, before I even started reading the specs, I was told by the maintainers at JSON Schema to focus on the architecture of the system, and to design the system in a way that would facilitate adding new JSON Schema drafts.&lt;/p&gt;

&lt;p&gt;I thought about it for a bit, and came up with an idea to have objects (let's call them keyword handler objects) that map the names of the keywords to functions containing the implementation for those keywords, and have an object for each supported draft.&lt;/p&gt;

&lt;p&gt;I started implementing, and soon realized that I didn't know what to do in some parts, like sure, I have a general idea of how some things would be done, and I wrote the code for a draft 2020-12 keyword handler object, but then I froze, I didn't know what to write in the functions, nor how this keyword handler object would be integrated with the rest of the system. So, I did some research, and I found out that there are two main architectures for JSON Schema Validators, those being the &lt;strong&gt;recursive architecture&lt;/strong&gt; and the &lt;strong&gt;visitor architecture&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The visitor architecture contained the missing pieces for me, it was basically what I was trying to do, but unlike me, it actually knew what to do in the keyword handler functions (I'll talk about it in more depth in a bit). I honestly didn't bother to fully read/understand the recursive architecture, but from what I understand, it's different from what I'm trying to do.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Visitor Architecture
&lt;/h3&gt;

&lt;p&gt;To be clear, both the recursive and visitor architectures are recursive, but in different ways.&lt;/p&gt;

&lt;p&gt;Basically this goes as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You have the main/public function that's used by anyone and everyone, let's call it &lt;code&gt;validate&lt;/code&gt;. This function uses a function that we'll call &lt;code&gt;validateSchema&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;validateSchema&lt;/code&gt; function is responsible for controlling the flow of the validator, it determines which part of the schema we'll visit and it uses the keyword handler object to get the handler function for each keyword&lt;/li&gt;
&lt;li&gt;The handler functions take three arguments, those being the &lt;strong&gt;schema&lt;/strong&gt;, &lt;strong&gt;instance&lt;/strong&gt;, and &lt;strong&gt;validation context&lt;/strong&gt;. The schema and instance should be pretty obvious, but the validation context deserves an explanation&lt;/li&gt;
&lt;li&gt;The validation context is an object that is used by the validator to help it work correctly. It takes notes on what's happening (by adding error objects whenever an error occurs, keeping track of the instance location and schema location, keeping track of the evaluated items and properties, etc.), and this information is later used to help the validator do its job. It could also contain references to functions that would be needed by the keyword handler functions&lt;/li&gt;
&lt;li&gt;When the &lt;code&gt;validateSchema&lt;/code&gt; function uses a keyword handler function, the function executes its logic, and at its end, it uses the &lt;code&gt;validateSchema&lt;/code&gt; function to give back control of the flow (the arguments should be children of the parent call to the &lt;code&gt;validateSchema&lt;/code&gt; function, so the schema argument should be a sub-schema, and so on)&lt;/li&gt;
&lt;li&gt;steps 2-5 are repeated until the validation is complete, and the validation context is then used by the &lt;code&gt;validate&lt;/code&gt; function to create the validation output result&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This architectural design allows us to separate the flow of the validation from the actual implementation of each keyword handler, which allows us to more easily add, update, or remove keywords from the system&lt;/p&gt;

&lt;h2&gt;
  
  
  Tooling &amp;amp; Implementation Notes
&lt;/h2&gt;

&lt;p&gt;I feel like it's worth mentioning that I've used and will probably continue to use LLMs to help me with my implementation.&lt;br&gt;
That being said, I am &lt;strong&gt;NOT&lt;/strong&gt; vibe coding. If something is written in my file, then I've either written it myself or thoroughly reviewed it beforehand.&lt;br&gt;
I've mainly used LLMs to either help me with syntax issues (since I'm new to Typescript), or to help me find solutions when I'm stuck (like with the visitor architecture).&lt;br&gt;
I'll probably use LLMs less often later on in the project, since my two main reasons for using LLMs should lessen over time.&lt;/p&gt;

&lt;p&gt;The code can be found on &lt;a href="https://github.com/AhmedHanyGamal/json-schema-validator" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jsonschema</category>
      <category>showdev</category>
      <category>typescript</category>
      <category>learning</category>
    </item>
    <item>
      <title>Implementing a JSON Schema Validator from Scratch - Week 2</title>
      <dc:creator>Ahmed Hany Gamal</dc:creator>
      <pubDate>Fri, 30 Jan 2026 20:35:01 +0000</pubDate>
      <link>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-2-497i</link>
      <guid>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-2-497i</guid>
      <description>&lt;p&gt;After two weeks of reading, I've finally finished the JSON Schema specifications (specifically the Core and Validation specs).&lt;/p&gt;

&lt;p&gt;At this point, I have a pretty good idea of what a JSON Schema Validator should look like, and I have a couple of things to say about the specs.&lt;/p&gt;

&lt;h2&gt;
  
  
  My thoughts on the specs
&lt;/h2&gt;

&lt;p&gt;Overall, I think the people who wrote the specs did a great job, pretty much every minute detail of the system was mentioned. How it should work, how the implementation should deal with certain cases, what the received schema should look like and what to do if it doesn't, etc.&lt;/p&gt;

&lt;p&gt;I did however face some difficulties reading the specs, this could be a result of a problem with the specs, &lt;strong&gt;or&lt;/strong&gt; a skill issue on my part, since this is my first time going through a specification.&lt;/p&gt;

&lt;p&gt;The difficulties I faced in certain parts of the specs were mostly a result of &lt;strong&gt;ambiguity of the designated audience&lt;/strong&gt; and &lt;strong&gt;lack of clarity&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ambiguity of the designated audience
&lt;/h3&gt;

&lt;p&gt;Basically, there are three different entities that the specs address, those being:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Schema Authors: The people that write schemas to use the validator&lt;/li&gt;
&lt;li&gt;Validator Implementers: The people that implement/write the code for the validator&lt;/li&gt;
&lt;li&gt;Specification Extenders: The people that write their own custom keywords and/or vocabularies&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My problem is that the specs don't explicitly tell you which one it's addressing, not only that, but the same paragraph, even the same sentence, could be talking to one of them at the start, and another one at the end.&lt;/p&gt;

&lt;p&gt;The only way to actually know who is being addressed is to fully understand what is being said, and that's really hard to do if you don't understand anything and it's your first time reading a JSON Schema specification.&lt;/p&gt;

&lt;p&gt;I imagine this won't be as prominent of a problem as it was if I read another JSON Schema specification (e.g. draft 2019-09), but it surely was a pain to deal with it this time.&lt;/p&gt;

&lt;p&gt;That being said, I honestly can't blame the people that wrote the specification. It would be really unpleasant to be reading a sentence, only to be interrupted twice just so that the specs could explicitly tell you that, yes, this sentence that you're reading is in fact talking to you, especially if you're already familiar with the specs and know that from the start.&lt;/p&gt;

&lt;h3&gt;
  
  
  lack of clarity
&lt;/h3&gt;

&lt;p&gt;This was a much bigger problem for me.&lt;/p&gt;

&lt;p&gt;The majority of the specs were incredibly detailed about everything, but certain parts were a bit unclear to me, which resulted in me either being unable to understand a topic (e.g. lexical vs dynamic scopes), or worse, misunderstanding the topic (e.g. meta-schemas - which I went into in detail in &lt;a href="https://dev.to/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-1-4ah9"&gt;last week's post&lt;/a&gt; - or the &lt;code&gt;anyOf&lt;/code&gt; example from &lt;a href="https://json-schema.org/draft/2020-12/json-schema-core#name-a-vocabulary-for-unevaluate" rel="noopener noreferrer"&gt;chapter 11&lt;/a&gt;). I just wish the people writing the specs would write a bit more to clarify what they really mean, and add one or two examples. Reading the specs would have been a much easier endeavor had that been the case.&lt;/p&gt;

&lt;p&gt;Again, I want to clarify that all of the issues and problems that I've mentioned could very well be a skill issue on my part, and in any case, the specs were overall great and the authors did an amazing job.&lt;/p&gt;

&lt;p&gt;Also, I'd like to shout out Google's notebookLM. I tried using multiple tools to help me understand the specs, and notebookLM was the absolute best.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation scope
&lt;/h2&gt;

&lt;p&gt;The specifications state that some keywords and features are mandatory to implement, while others are optional. I'll state here what I'm planning to do.&lt;/p&gt;

&lt;h3&gt;
  
  
  initial implementation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;I will only support draft 2020-12&lt;/li&gt;
&lt;li&gt;I will NOT support the &lt;code&gt;$vocabulary&lt;/code&gt; keyword&lt;/li&gt;
&lt;li&gt;I will only support the detailed output format&lt;/li&gt;
&lt;li&gt;I will NOT support short-circuiting&lt;/li&gt;
&lt;li&gt;I will only support the annotation functionality of the &lt;code&gt;format&lt;/code&gt; keyword&lt;/li&gt;
&lt;li&gt;I will NOT support dereferencing of JSON pointers that use the schema's parent or ancestor base URI (as per &lt;a href="https://json-schema.org/draft/2020-12/json-schema-core#name-json-pointer-fragments-and-" rel="noopener noreferrer"&gt;section 9.2.1&lt;/a&gt; of the Core specs)&lt;/li&gt;
&lt;li&gt;I will NOT support remote schema fetching&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The idea here is that I want to lower the difficulty as much as possible in the initial implementation, since this is my first time implementing a fully spec compliant software system, which I imagine would take a good amount of time and effort to finish.&lt;/p&gt;

&lt;h3&gt;
  
  
  implementation extensions
&lt;/h3&gt;

&lt;p&gt;When I do have a basic fully functional validator, I &lt;em&gt;may&lt;/em&gt; choose to add any of the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;another draft: in order to design an architecturally resilient validator, it shouldn't be incredibly difficult to add a new draft to the already existing system&lt;/li&gt;
&lt;li&gt;short-circuiting: though I'd need to make sure I'd do it in a way that complies with the &lt;a href="https://json-schema.org/draft/2020-12/json-schema-core#name-keyword-behaviors" rel="noopener noreferrer"&gt;specs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;format&lt;/code&gt; keyword assertions: if I see any learning value from doing this or find that it could be fun, I could do it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'll be posting weekly updates on my journey here.&lt;br&gt;
The code can be found on &lt;a href="https://github.com/AhmedHanyGamal/json-schema-validator" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jsonschema</category>
      <category>showdev</category>
      <category>typescript</category>
      <category>learning</category>
    </item>
    <item>
      <title>Implementing a JSON Schema Validator from Scratch - Week 1</title>
      <dc:creator>Ahmed Hany Gamal</dc:creator>
      <pubDate>Fri, 23 Jan 2026 23:41:28 +0000</pubDate>
      <link>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-1-4ah9</link>
      <guid>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-1-4ah9</guid>
      <description>&lt;p&gt;Going into this week, the plan was to go through the "Getting started" page in the &lt;a href="https://json-schema.org/" rel="noopener noreferrer"&gt;JSON Schema website&lt;/a&gt; and read the draft 2020-12 specs. How naively optimistic of me.&lt;/p&gt;

&lt;p&gt;I went through the "Getting started" page to refresh my mind on JSON Schema and most of its keywords, then I started reading the specs.&lt;/p&gt;

&lt;p&gt;It turned out that there are two separate documents for the draft 2020-12 specs, one containing the keywords and details relevant to the architecture and design of JSON Schema as a whole (&lt;a href="https://json-schema.org/draft/2020-12/json-schema-core" rel="noopener noreferrer"&gt;JSON Schema Core&lt;/a&gt;), and another containing the details for the validation keywords (&lt;a href="https://json-schema.org/draft/2020-12/json-schema-validation" rel="noopener noreferrer"&gt;JSON Schema Validation&lt;/a&gt;). There's also the &lt;a href="https://datatracker.ietf.org/doc/html/draft-bhutton-relative-json-pointer-00" rel="noopener noreferrer"&gt;Relative JSON Pointers document&lt;/a&gt;, but I'm not sure where this fits into the whole picture, I'm guessing it just explains how relative JSON pointers work in greater detail.&lt;/p&gt;

&lt;p&gt;I ended up only reading the first 8 chapters of the Core specs.&lt;br&gt;
In hindsight, this should have been expected, especially since this is my first time dealing with something like this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial thoughts on the specs
&lt;/h2&gt;

&lt;p&gt;It was surprising to see how a document could explain the proper way to implement an entire system without leaving any ambiguities, every minute detail is mentioned with the reason behind it and everything.&lt;/p&gt;

&lt;p&gt;But all that being said, the nature of what is required of a specification makes it really hard to actually read or write it, by that I mean that explaining a system as sophisticated and elegant as JSON Schema with only a few words is a really difficult task, and even though all of the system's details are mentioned, some parts are just really hard to put into words, which made some parts relatively hard to understand, and other parts incredibly easy to &lt;strong&gt;misunderstand&lt;/strong&gt; (I'll be talking about all that in a second).&lt;/p&gt;

&lt;h2&gt;
  
  
  The difficulties of the specs
&lt;/h2&gt;

&lt;p&gt;Most of the topics weren't that difficult individually (though as we'll later see, some certainly were), but the whole process of reading the specs and understanding it certainly is.&lt;br&gt;
The difficulty comes from the fact that this specification explains an entire system, an entire world if you will, a world that you've just found yourself in with no prior experience to what's in it and how things work there, so the difficulty arises from the sheer number of things that you need to learn and connect together in order to understand how this system/world works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Topics I misunderstood
&lt;/h2&gt;

&lt;p&gt;These are topics that I thought I understood, only to later realize that my understanding was completely incorrect&lt;/p&gt;

&lt;h3&gt;
  
  
  meta-schemas
&lt;/h3&gt;

&lt;p&gt;The first time I saw the term "meta-schema" was in the &lt;a href="https://json-schema.org/learn/glossary#meta-schema" rel="noopener noreferrer"&gt;JSON Schema Glossary&lt;/a&gt;. There it said that a meta-schema is simply a schema that is used to validate another schema, meaning that the other schema is treated as an instance in the validation process. When I read the first few chapters of the specs, I believe I saw that definition again, but then later the &lt;code&gt;$vocabulary&lt;/code&gt; keyword was mentioned and it became clear that something was off.&lt;/p&gt;

&lt;p&gt;What I came to later realize was that though the previous definition isn't &lt;em&gt;wrong&lt;/em&gt;, it fails to mention some incredibly crucial details, which makes this definition incredibly misleading.&lt;/p&gt;

&lt;p&gt;When I read this definition I thought that if I use a schema to validate an instance, and that instance happened to also be a schema, then the schema that I'm using for validation is a meta-schema.&lt;br&gt;
It turns out that it's much more complicated than that.&lt;/p&gt;

&lt;p&gt;When you initially use/load a schema, there are some steps that need to be taken before you actually validate any instances. First, you use the URI in &lt;code&gt;$schema&lt;/code&gt; (for example &lt;a href="https://json-schema.org/draft/2020-12/schema" rel="noopener noreferrer"&gt;https://json-schema.org/draft/2020-12/schema&lt;/a&gt; in the case of draft 2020-12) to get a schema from that URI, you then check the &lt;a href="https://json-schema.org/learn/glossary#vocabulary" rel="noopener noreferrer"&gt;vocabularies&lt;/a&gt; from the &lt;code&gt;$vocabulary&lt;/code&gt; of that schema and make sure that the implementation supports the required vocabularies, if it does then you run that schema on your original schema to make sure that the schema you're using complies with the &lt;a href="https://json-schema.org/learn/glossary#draft" rel="noopener noreferrer"&gt;draft&lt;/a&gt;/&lt;a href="https://json-schema.org/learn/glossary#dialect" rel="noopener noreferrer"&gt;dialect&lt;/a&gt; that you're using, if that validation succeeds, only then do you actually start using your original schema to validate JSON instances.&lt;br&gt;
In that whole process, the schema that we initially got from the &lt;code&gt;$schema&lt;/code&gt; URI, that is the meta-schema.&lt;/p&gt;

&lt;p&gt;So, the original definition isn't &lt;em&gt;wrong&lt;/em&gt;, but it is incredibly misleading, and it doesn't help that the specs don't explicitly mention that fact, it just gives you bits and pieces in different parts of the document and lets you figure it out on your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Topics I don't understand yet
&lt;/h2&gt;

&lt;p&gt;These are topics that I still haven't fully grasped, I have a general idea of what it's about, but I still don't understand it&lt;/p&gt;

&lt;h3&gt;
  
  
  lexical vs dynamic scopes/keywords
&lt;/h3&gt;

&lt;p&gt;From what I understand, this is one of the most difficult topics in the specs, so I think it's normal for me to not understand right away.&lt;br&gt;
I think I may already understand what the lexical scope is and how it works, I assume it's basically just the default/intuitive method of dealing with scope, while the dynamic scope is a bit different and more complex/unintuitive, as it's made for very specific cases with very specific needs.&lt;br&gt;
I'll do my best to understand this next week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There are more topics that I didn't mention in this post, like different keywords types (Annotations, Assertions, Applicators, etc.) and how they function, the differences between the different types of schemas (resource schema, sub-schema, embedded schema, etc.), and other things, but these were all relatively straightforward, plus this post would be incredibly long if I did, and it's already pretty long.&lt;/p&gt;

&lt;p&gt;I usually don't enjoy reading, as a matter of fact, I usually hate reading, but this was a surprisingly enjoyable experience, not saying it was easy, far from it, but you just get a weird dopamine rush when you finally understand a topic that you've spent 5 consecutive hours trying to figure out.&lt;/p&gt;

&lt;p&gt;I'll probably start actually writing code for this project either by the end of week 2, or the beginning of week 3.&lt;/p&gt;

&lt;p&gt;I'll be posting weekly updates on my journey here.&lt;br&gt;
The code (or lack thereof at this point in time) can be found on &lt;a href="https://github.com/AhmedHanyGamal/json-schema-validator" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jsonschema</category>
      <category>learning</category>
      <category>typescript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Implementing a JSON Schema Validator from Scratch - Week 0</title>
      <dc:creator>Ahmed Hany Gamal</dc:creator>
      <pubDate>Fri, 16 Jan 2026 19:37:13 +0000</pubDate>
      <link>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-0-2ee0</link>
      <guid>https://forem.com/ahmedhanygamal/implementing-a-json-schema-validator-from-scratch-week-0-2ee0</guid>
      <description>&lt;p&gt;In an attempt to deepen my understanding of JSON Schema and how it works, I've decided to implement a validator from scratch.&lt;/p&gt;

&lt;p&gt;For those of you who don't know what JSON Schema is, it's a declarative language used to validate JSON documents, ensuring they follow a specific structure. You can find more details &lt;a href="https://json-schema.org/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My roadmap consists of the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read the specs&lt;/li&gt;
&lt;li&gt;Take a look at existing implementations&lt;/li&gt;
&lt;li&gt;Write the code for testing using the &lt;a href="https://github.com/json-schema-org/JSON-Schema-Test-Suite" rel="noopener noreferrer"&gt;JSON-Schema-Test-Suite&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Implement the validator using &lt;a href="https://json-schema.org/draft/2020-12/json-schema-core" rel="noopener noreferrer"&gt;Draft 2020-12&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Support another draft like &lt;a href="https://json-schema.org/draft-07/draft-handrews-json-schema-01" rel="noopener noreferrer"&gt;Draft-07&lt;/a&gt; in the implementation (optional)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I plan on supporting multiple drafts in my implementation to focus on architectural decisions, though I might skip this step if I find that the scope of this project is getting out of hand&lt;/p&gt;

&lt;p&gt;I’ll be building this project using Typescript. I am learning the language as I go, so this project will serve as a practical way to pick it up while I work through the specification.&lt;/p&gt;

&lt;p&gt;I'll be posting weekly updates on my journey here.&lt;br&gt;
The code can be found on &lt;a href="https://github.com/AhmedHanyGamal/json-schema-validator" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>jsonschema</category>
      <category>showdev</category>
      <category>typescript</category>
      <category>learning</category>
    </item>
  </channel>
</rss>
