Modern utility library and typescript typings for building JSON Schema documents dynamically
- Build JSON Schema documents for various drafts (currently only draft-2020-12 but more coming soon)
- Strongly typed documents using Typescript
- Allows you to build correct JSON Schema documents using dynamic data
Create a simple draft-2020-12 document:
import { s } from "json-schema-fns";
const schema = s.object({
properties: [s.requiredProperty("foo", s.string()), s.property("bar", s.int())],
});
schema.toSchemaDocument();
Will result in
{
"$schema": "https://json-schema.org/draft/2020-12/schema#",
"$id": "https://jsonhero.io/schemas/root.json",
"type": "object",
"properties": {
"foo": { "type": "string" },
"bar": { "type": "integer" }
},
"required": ["foo"]
}
You can also import the types for a specific draft to use, like so:
import { s, Schema, IntSchema, StringSchema, StringFormat } from "json-schema-fns";
function buildIntSchema(maximum: number, minimum: number): IntSchema {
return s.int({ minimum, maximum });
}
function buildStringFormat(format: JSONStriStringFormatgFormat): StringSchema {
return s.string({ format });
}
json-schema-fns
support all the features of JSON schema:
import { s } from "json-schema-fns";
const phoneNumber = s.def("phoneNumber", s.string({ pattern: "^[0-9]{3}-[0-9]{3}-[0-9]{4}$" }));
const usAddress = s.def(
"usAddress",
s.object({
properties: [s.requiredProperty("zipCode", s.string())],
}),
);
const ukAddress = s.def(
"ukAddress",
s.object({
properties: [s.requiredProperty("postCode", s.string())],
}),
);
s.object({
$id: "/schemas/person",
title: "Person Profile",
description: "Attributes of a person object",
examples: [
{
name: "Eric",
email: "[email protected]",
},
],
$comment: "This is just a preview",
default: {},
properties: [
s.requiredProperty("name", s.string()),
s.property("email", s.string({ format: "email" })),
s.property("phoneNumber", s.ref("phoneNumber")),
s.property("billingAddress", s.oneOf(s.ref("ukAddress"), s.ref("usAddress"))),
s.patternProperty("^[A-Za-z]$", s.string()),
],
additionalProperties: s.array({
items: s.number({ minimum: 0, maximum: 5000 }),
}),
propertyNames: "^[A-Za-z_][A-Za-z0-9_]*$",
minProperties: 3,
maxProperties: 20,
unevaluatedProperties: false,
defs: [phoneNumber, usAddress, ukAddress],
}).toSchemaDocument();
Will result in
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"$id": "/schemas/person",
"title": "Person Profile",
"description": "Attributes of a person object",
"examples": [
{
"name": "Eric",
"email": "[email protected]"
}
],
"$comment": "This is just a preview",
"default": {},
"minProperties": 3,
"maxProperties": 20,
"unevaluatedProperties": false,
"properties": {
"name": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"phoneNumber": {
"$ref": "#/$defs/phoneNumber"
},
"billingAddress": {
"oneOf": [
{
"$ref": "#/$defs/ukAddress"
},
{
"$ref": "#/$defs/usAddress"
}
]
}
},
"required": ["name"],
"patternProperties": {
"^[A-Za-z]$": {
"type": "string"
}
},
"propertyNames": {
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
},
"additionalProperties": {
"type": "array",
"items": {
"type": "number",
"minimum": 0,
"maximum": 5000
}
},
"$defs": {
"phoneNumber": {
"type": "string",
"pattern": "^[0-9]{3}-[0-9]{3}-[0-9]{4}$"
},
"usAddress": {
"type": "object",
"properties": {
"zipCode": {
"type": "string"
}
},
"required": ["zipCode"]
},
"ukAddress": {
"type": "object",
"properties": {
"postCode": {
"type": "string"
}
},
"required": ["postCode"]
}
}
}
All the builder methods for creating subschemas are available on the s
object
import { s } from "json-schema-fns";
Or if you want to import a specific dialect:
import { s } from "json-schema-fns/2020";
All builder methods return a SchemaBuilder
, and you can generate the JSON schema created by the builder using toSchemaDocument
like so
s.object().toSchemaDocument();
Which will result in the following document
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object"
}
If you don't want the $schema
property, use toSchema
instead:
s.object().toSchema(); // { "type": "object" }
All builder methods also support the options in AnnotationSchema
:
s.object({
$id: "#/foobar",
$comment: "This is a comment",
default: {},
title: "FooBar Object Schema",
description: "This is the FooBar schema description",
examples: [{ foo: "bar" }],
deprecated: true,
readOnly: true,
writeOnly: false,
}).toSchema();
Produces the schema
{
"type": "object",
"$id": "#/foobar",
"$comment": "This is a comment",
"default": {},
"title": "FooBar Object Schema",
"description": "This is the FooBar schema description",
"examples": [{ "foo": "bar" }],
"deprecated": true,
"readOnly": true,
"writeOnly": false
}
Builds a schema of type object
, accepting a single argument of type ObjectOptions
An array of optional and required properties
s.object({
properties: [
s.property("name", s.string()),
s.requiredProperty("email", s.string({ format: "email" })),
],
}).toSchema();
Produces the schema
{
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string", "format": "email" }
},
"required": ["email"]
}
You can also add patternProperties
s.object({ properties: [s.patternProperty("^S_", s.string())] }).toSchema();
which produces the schema
{
"type": "object",
"patternProperties": {
"^S_": { "type": "string" }
}
}
Add an additonalProperties schema:
s.object({ additionalProperties: s.number() }).toSchema();
Produces the schema
{
"type": "object",
"additionalProperties": {
"type": "number"
}
}
Add a propertyNames pattern:
s.object({ propertyNames: "^[A-Za-z_][A-Za-z0-9_]*$" }).toSchema();
Produces the schema
{
"type": "object",
"propertyNames": {
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
}
}
Validate the number of properties in an object using min/maxProperties
s.object({ minProperties: 4, maxProperties: 10 }).toSchema();
Produces the schema
{
"type": "object",
"minProperties": 4,
"maxProperties": 10
}
Specify the handling of unevaluatedProperties
s.object({ unevaluatedProperties: false }).toSchema();
Produces the schema
{
"type": "object",
"unevaluatedProperties": false
}
Builds a schema of type array
, accepting a single argument of type ArrayOptions
Define the items schema for an array:
s.array({ items: s.string() }).toSchema();
Produces the schema
{
"type": "array",
"items": { "type": "string" }
}
Define the array length
s.array({ contains: { schema: s.number(), min: 1, max: 3 }).toSchema();
Produces the schema
{
"type": "array",
"contains": { "type": "number" },
"minContains": 1,
"maxContains": 3
}
Allows you to perform tuple validation:
s.array({ prefixItems: [s.string(), s.number()] }).toSchema();
Produces the schema
{
"type": "array",
"prefixItems": [{ "type": "string" }, { "type": "number" }]
}
Define the schema for unevaluatedItems
s.array({ unevaluatedItems: s.object() }).toSchema();
Produces the schema
{
"type": "array",
"unevaluatedItems": { "type": "object" }
}
Define the schema contains
s.array({ contains: { schema: s.number(), min: 1, max: 3 }).toSchema();
Produces the schema
{
"type": "array",
"contains": { "type": "number" },
"minContains": 1,
"maxContains": 3
}
- Support draft-04
- Support draft-06
- Support draft-07
- Support draft/2019-09