JSON Schema is a declarative language for annotating and validating JSON document's structure, constraints, and data types. It helps you standardize and define expectations for JSON data.
Zoi provides functionality to convert its type definitions into JSON Schema format, enabling seamless integration with systems that utilize JSON Schema for data validation and documentation. It also supports decoding existing JSON Schemas back into Zoi schemas via Zoi.from_json_schema/1.
Examples
Encoding a Zoi schema:
iex> schema = Zoi.map(%{name: Zoi.string(), age: Zoi.integer()})
iex> Zoi.to_json_schema(schema)
%{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: :object,
properties: %{
name: %{type: :string},
age: %{type: :integer}
},
required: [:name, :age],
additionalProperties: false
}Decoding a JSON Schema:
iex> json = %{"type" => "object", "properties" => %{"name" => %{"type" => "string"}}, "required" => ["name"]}
iex> schema = Zoi.from_json_schema(json)
iex> Zoi.parse(schema, %{"name" => "Alice"})
{:ok, %{"name" => "Alice"}}Type mapping
| Zoi | JSON Schema |
|---|---|
Zoi.string/1 | "string" |
Zoi.integer/1 | "integer" |
Zoi.float/1 | "number" |
Zoi.number/1 | "number" |
Zoi.decimal/1 | "number" |
Zoi.boolean/1 | "boolean" |
Zoi.null/1 | "null" |
Zoi.literal/2 | const |
Zoi.enum/2 | enum |
Zoi.array/2 | "array" |
Zoi.tuple/2 | "array" with prefixItems |
Zoi.map/2 | "object" |
Zoi.union/2 | oneOf (decode also accepts anyOf) |
Zoi.intersection/2 | allOf |
Zoi.nullable/2 | nullable type via oneOf |
Zoi.date/1 and Zoi.ISO.date/1 | "string" with format: "date" |
Zoi.datetime/1 and Zoi.ISO.datetime/1 | "string" with format: "date-time" |
Zoi.naive_datetime/1 and Zoi.ISO.naive_datetime/1 | "string" with format: "date-time" |
Zoi.time/1 and Zoi.ISO.time/1 | "string" with format: "time" |
Zoi.email/1 | "string" with format: "email" |
Zoi.url/1 | "string" with format: "uri" |
Zoi.uuid/1 | "string" with format: "uuid" |
Metadata
Zoi.to_json_schema/1 incorporates description, example, and deprecated
options into the resulting JSON Schema:
iex> schema = Zoi.string(description: "A simple string", example: "Hello, World!")
iex> Zoi.to_json_schema(schema)
%{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: :string,
description: "A simple string",
example: "Hello, World!"
}When a schema is marked as deprecated, the generated JSON Schema will include
deprecated: true (the deprecation message itself is not part of JSON Schema):
iex> schema = Zoi.string(deprecated: "Use another field")
iex> Zoi.to_json_schema(schema)
%{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: :string,
deprecated: true
}Additional JSON Schema annotations can be set via the :metadata option.
The recognised keys are :title, :examples, :read_only, :write_only, :id, :comment, :content_encoding and :content_media_type. They are emitted as the matching JSON Schema keywords ($id and $comment for :id and :comment):
iex> schema = Zoi.string(metadata: [title: "Username", examples: ["alice", "bob"], read_only: true])
iex> Zoi.to_json_schema(schema)
%{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: :string,
title: "Username",
examples: ["alice", "bob"],
readOnly: true
}Limitations
- Complex types or custom types not listed above will raise an error during conversion.
- Some advanced
Zoifeatures may not have direct equivalents in JSON Schema. - Refinements are partially supported, primarily for string patterns and length constraints.
- Additional properties in objects are disallowed by default (
additionalProperties: false).
References
Summary
Functions
@spec decode(map()) :: Zoi.schema()
Decodes a JSON Schema map into a Zoi schema.
The input must be a JSON-shaped map with string keys, as produced by a JSON parser.
Examples
iex> json = %{"type" => "object", "properties" => %{"name" => %{"type" => "string"}}, "required" => ["name"]}
iex> schema = Zoi.JSONSchema.decode(json)
iex> Zoi.parse(schema, %{"name" => "Alice"})
{:ok, %{"name" => "Alice"}}
@spec encode(Zoi.schema()) :: map()
Encodes a Zoi schema into a JSON Schema map.
Examples
iex> schema = Zoi.map(%{name: Zoi.string()})
iex> Zoi.JSONSchema.encode(schema)
%{
"$schema": "https://json-schema.org/draft/2020-12/schema",
type: :object,
properties: %{name: %{type: :string}},
required: [:name],
additionalProperties: false
}