JSON Schema basics: a standard for validating data shape

3 min read

JSON Schema is the standard for defining and validating the shape of JSON data. It powers OpenAPI specs, editor autocomplete for config files, and a lot of API request validation. This article walks through the core keywords and the pitfalls.

What it is

JSON Schema is a spec (IETF Draft) for describing JSON data using JSON.

{
	"type": "object",
	"properties": {
		"name": { "type": "string" },
		"age": { "type": "integer", "minimum": 0 }
	},
	"required": ["name"]
}

Against this schema, { "name": "Alice", "age": 30 } is valid; { "age": -5 } is invalid (missing name, negative age).

Core keywords

type

{ "type": "string" }
{ "type": "integer" }
{ "type": "number" }
{ "type": "boolean" }
{ "type": "array" }
{ "type": "object" }
{ "type": "null" }

Multiple types:

{ "type": ["string", "null"] }

Object properties

{
	"type": "object",
	"properties": {
		"id": { "type": "integer" },
		"name": { "type": "string" }
	},
	"required": ["id", "name"],
	"additionalProperties": false
}

Without additionalProperties: false, unknown keys pass through silently. Forgetting it is a common bug source.

Arrays

{
	"type": "array",
	"items": { "type": "integer" },
	"minItems": 1,
	"maxItems": 100
}

String constraints

{
	"type": "string",
	"minLength": 3,
	"maxLength": 50,
	"pattern": "^[A-Z][a-z]+$",
	"format": "email"
}

format recognizes email, uri, date-time, uuid, and so on. Validators differ on how strictly they enforce these.

Number constraints

{
	"type": "integer",
	"minimum": 0,
	"maximum": 100,
	"exclusiveMinimum": 0
}

Beyond the basics

enum

{ "enum": ["red", "green", "blue"] }

Works for any value type, not just strings.

oneOf / anyOf / allOf

{
	"oneOf": [{ "type": "string" }, { "type": "integer" }]
}
  • oneOf — matches exactly one
  • anyOf — matches at least one
  • allOf — matches all

$ref for reuse

{
	"$defs": {
		"address": {
			"type": "object",
			"properties": {
				"street": { "type": "string" },
				"city": { "type": "string" }
			}
		}
	},
	"type": "object",
	"properties": {
		"shipping": { "$ref": "#/$defs/address" },
		"billing": { "$ref": "#/$defs/address" }
	}
}

Reuse common shapes via $ref. OpenAPI puts these under components.schemas and references them across paths.

Where it shows up

1. API specs (OpenAPI / Swagger)

OpenAPI uses JSON Schema for request/response shapes, enabling docs, mock servers, and client generation.

2. Config files

VS Code, ESLint, Prettier publish JSON Schemas; editors use them for autocomplete and inline validation.

3. Form / request validation

On the server, libraries like Ajv accept a JSON Schema and validate incoming bodies against it.

4. Database constraints

Postgres JSONB columns can enforce a JSON Schema via a CHECK constraint.

Common traps

1. Forgetting additionalProperties

{
	"properties": {
		"name": { "type": "string" }
	}
}

This says “if name exists it must be a string”. Unknown keys pass without complaint. Set additionalProperties: false for strict shapes.

2. integer vs number

number accepts floats; integer accepts whole numbers. Validators disagree on how to handle 1.0 against integer.

3. format enforcement varies

format: "email" regex differs across validators. For real email validation, use a dedicated library.

4. Nullable representations differ

OpenAPI 3.0 uses nullable: true; pure JSON Schema uses type: ["string", "null"]. Don’t mix them.

Summary

  • JSON Schema describes JSON shape in JSON.
  • Core keywords: type, properties, required, additionalProperties.
  • $ref for reuse; oneOf, anyOf, allOf for combinations.
  • Used in API specs, config files, form validation.

To check that JSON conforms to a schema, the JSON validator on this site accepts both inputs and reports mismatches.