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.any/1 | unconstrained schema ({}) |
Zoi.none/1 | false |
Zoi.literal/2 | const |
Zoi.enum/2 | enum |
Zoi.array/2 | "array" |
Zoi.map_set/2 | "array" with uniqueItems |
Zoi.tuple/2 | "array" with prefixItems |
Zoi.map/2 | "object" |
Zoi.struct/3 | "object" (the Elixir module is not encoded) |
Zoi.union/2 | anyOf |
Zoi.exclusive_union/2 | oneOf |
Zoi.intersection/2 | allOf |
Zoi.nullable/2 | nullable type via anyOf |
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() | boolean()) :: Zoi.schema()
Decodes a JSON Schema map or boolean into a Zoi schema.
Maps must have string keys, as produced by a JSON parser.
true accepts any value; false rejects every value.
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() | boolean()
Encodes a Zoi schema into a JSON Schema map or boolean.
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
}