Defining Schemas
View SourceThis guide explains the different possible values to use as a schema with JSV.
Schema sources
Schemas given as input to JSV can come from two sources:
- Schemas given directly to the
JSV.build/2
function. These are expected to be maps or booleans. JSV will not parse JSON strings. - Schemas returned by resolvers. These should also be maps (but not booleans). The built-in resolvers will handle JSON deserialization automatically.
JSV is designed to work with raw schemas. Any map or boolean is a valid schema. For instance, it is possible to directly use a schema from a file:
root =
"my-schema.json"
|> File.read!()
|> JSON.decode!()
|> JSV.build()
Schema formats
Schemas can be either booleans or maps. The true
value is equivalent to an
empty JSON Schema {}
, while false
is a schema that will invalidate any
value. It is most often used as a sub-schema for additionalProperties
.
Maps can define keys and values as binaries or atoms. The following schemas are equivalent:
%{type: :boolean}
%{type: "boolean"}
%{"type" => "boolean"}
%{"type" => :boolean} # You will rarely find this one in the wild!
This is because JSV will normalize the schemas before building a "root", the base data structure for data validation.
Note that mixing keys is not recommended. In the following example, JSV will build a schema that will successfully validate integers with a minimum of zero. However, the choice for the maximum value is not made by JSV.
%{:type => :integer, "minimum" => 0, "maximum" => 10, :maximum => 20}
Struct schemas
Schemas can be used to define structs.
For instance, with this module definition schema:
defmodule MyApp.UserSchema do
import JSV
defschema(%{
type: :object,
properties: %{
name: %{type: :string, default: ""},
age: %{type: :integer, default: 0}
}
})
end
A struct will be defined with the appropriate default values:
iex> %MyApp.UserSchema{}
%MyApp.UserSchema{name: "", age: 0}
The module can be used as a schema to build a validator root and cast data to the corresponding struct:
iex> {:ok, root} = JSV.build(MyApp.UserSchema)
iex> data = %{"name" => "Alice"}
iex> JSV.validate(data, root)
{:ok, %MyApp.UserSchema{name: "Alice", age: 0}}
Casting to a struct can be disabled by passing cast: false
into the
options of JSV.validate/3
.
iex> {:ok, root} = JSV.build(MyApp.UserSchema)
iex> data = %{"name" => "Alice", "extra" => "hello!"}
iex> JSV.validate(data, root, cast: false)
{:ok, %{"name" => "Alice", "extra" => "hello!"}}
The module can also be used in other schemas:
%{
type: :object,
properties: %{
name: %{type: :string},
owner: MyApp.UserSchema
}
}
Struct defining schemas are a special case of the generic cast mechanism built in JSV. Make sure to check that guide out as well.