The JSONSchema.make function allows you to generate a JSON Schema from a predefined schema.
Example
Here’s an example where we define a schema for a “Person” with properties “name” (a string) and “age” (a number)
and we generate the corresponding JSON Schema.
The JSONSchema.make function aims to produce an optimal JSON Schema representing the input part of the decoding phase. It does this by traversing the schema from the most nested component, incorporating each refinement, and stops at the first transformation encountered.
Consider a modification to the schema of the age field:
The new JSON Schema for the age field shows it as type "integer", keeping the refinement of being an integer and excluding the transformation that clamps the value between 1 and 10.
Specific Outputs for Schema Types
Literals
Literals are transformed into enum types within JSON Schema:
Single literal
Union of literals
Void
Any
Unknown
Object
String
Number
Boolean
Tuples
Arrays
Non Empty Arrays
Structs
Records
Mixed Structs with Records
Enums
Template Literals
Unions
Unions are expressed using anyOf or enum, depending on the types involved:
Generic Union
Union of literals
Identifier Annotations
You can augment your schemas with identifier annotations to enhance their structure and maintainability.
When you utilize these annotations, your schemas are included within a “$defs” object property at the root of the JSON Schema and referenced from there, enabling better organization and readability.
By structuring your JSON Schema with identifier annotations, each annotated schema is clearly defined in a separate section, making the entire schema easier to navigate and maintain. This approach is especially useful for complex schemas that require clear documentation of each component.
Standard JSON Schema Annotations
Standard JSON Schema annotations such as title, description, default, and examples are supported.
These annotations allow you to enrich your schemas with metadata that can enhance readability and provide additional information about the data structure.
Adding annotations to Struct properties
To enhance the clarity of your JSON schemas, it’s advisable to add annotations directly to the property signatures rather than to the type itself.
This method is more semantically appropriate as it links descriptive titles and other metadata specifically to the properties they describe, rather than to the generic type.
Recursive and Mutually Recursive Schemas
Recursive and mutually recursive schemas are supported, however it’s mandatory to use identifier annotations for these types of schemas to ensure correct references and definitions within the generated JSON Schema.
In this example, the Category schema refers to itself, making it necessary to use an identifier annotation to facilitate the reference.
Custom JSON Schema Annotations
When working with JSON Schema certain data types, such as bigint, lack a direct representation because JSON Schema does not natively support them.
This absence typically leads to an error when the schema is generated:
To address this, you can enhance the schema with a custom annotation, defining how you intend to represent such types in JSON Schema:
Refinements
When defining a refinement (e.g., through the filter function), you can attach a JSON Schema annotation to your schema containing a JSON Schema “fragment” related to this particular refinement.
This fragment will be used to generate the corresponding JSON Schema.
Note that if the schema consists of more than one refinement, the corresponding annotations will be merged.
The jsonSchema annotation is intentionally defined as a generic object. This allows it to describe non-standard extensions.
As a result, the responsibility of enforcing type constraints is left to you, the user.
If you prefer stricter type enforcement or need to support non-standard extensions, you can introduce a satisfies constraint on the object literal. This constraint should be used in conjunction with the typing library of your choice.
Example
In the following example, we’ve used the @types/json-schema package to provide TypeScript definitions for JSON Schema. This approach not only ensures type correctness but also enables autocomplete suggestions in your IDE.
For all other types of schema that are not refinements, the content of the annotation is used and overrides anything the system would have generated by default:
Specialized JSON Schema Generation with Schema.parseJson
When utilizing Schema.parseJson, JSON Schema generation follows a specialized approach. Instead of merely generating a JSON Schema for a string—which would be the default output representing the “from” side of the transformation defined by Schema.parseJson—it specifically generates the JSON Schema for the actual schema provided as an argument.