View Source Icon.Schema behaviour (ICON 2.0 SDK v0.2.3)
This module defines a schema.
Schemas serve the purpose of validating both requests and responses. The idea is to have a map defining the types and validations for our JSON payloads.
defining-schemas
Defining Schemas
A schema can be either anonymous or not. For non-anonymous schemas, we need to
use
this module and define a schema using defschema/1
e.g. the following is
an (incomplete) transaction.
defmodule Transaction do
use Icon.Schema
defschema(%{
from: {:eoa_address, required: true},
to: {:address, required: true},
value: {:loop, default: 0}
})
end
As seen in the previous example, the values change depending on the types and options each key has. The available primitive types are:
:address
(same asIcon.Schema.Types.Address
).:any
(does nothing with the data).:binary_data
(same asIcon.Schema.Types.BinaryData
).:boolean
(same asIcon.Schema.Types.Boolean
).:eoa_address
(same asIcon.Schema.Types.EOA
).:error
(same asIcon.Schema.Error
).:event_log
(same asIcon.Schema.Types.EventLog
).:hash
(same asIcon.Schema.Types.Hash
).:integer
(same asIcon.Schema.Types.Integer
).:loop
(same asIcon.Schema.Types.Loop
).:pos_integer
(same asIcon.Schema.Types.PosInteger
).:score_address
(same asIcon.Schema.Types.SCORE
).:signature
(same asIcon.Schema.Types.Signature
).:string
(same asIcon.Schema.Types.String
).:timestamp
(same asIcon.Schema.Types.Timestamp
).enum([atom()])
(same as{:enum, [atom()]}
).
Then we have complex types:
- Anonymous schema:
t()
. - A homogeneous list of type
t
:list(t)
. - Any of the types listed in the list:
any([{atom(), t}], atom())
. The first atom is the value of the second atom in the params.
Additionally, we can implement our own primite types and named schemas with
the Icon.Schema.Type
behaviour and this behaviour respectively. The
module name should be used as the actual type.
The available options are the following:
default
- Default value for the key. It can be a closure for late binding.required
- Whether the key is required or not.field
- Name of the key to check to choose the rightany()
type. This value should be anatom()
, so it'll probably come from anenum()
type.
Note:
nil
and""
are considered empty values. They will be ignored for not mandatory keys and will add errors for mandatory keys.
variable-keys
Variable Keys
In certain cases, the keys of a map will not be defined in advaced. The
wildcard key ":$variable"
can be used to catch those variable keys e.g. the
following schema defines a map of variable keys that map to :loop
values:
%{"$variable": :loop}
So, if we get the following:
%{
"0" => "0x2a",
"1" => "0x54"
}
it will load it as follows:
%{
"0" => 42,
"1" => 84
}
schema-caching
Schema Caching
When a schema is generated with the function generate/1
, it is also cached
as a :persistent_term
in order to avoid generating the same thing twice.
This makes the first schema generation slower, but accessing the generated
schema should be then quite fast.
schema-struct
Schema Struct
When defining a schema with use Icon.Schema
, we can use the apply/2
function to put the loaded data into the struct e.g. for the following schema:
defmodule Block do
use Icon.Schema
defschema(%{
height: :pos_integer,
hash: :hash
transactions: list(Transaction)
})
end
we can then validate a payload with the following:
payload = %{
"height" => "0x2a",
"hash" => "c71303ef8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238",
"transactions" => [
%{
"from" => "hxbe258ceb872e08851f1f59694dac2558708ece11",
"to" => "cxb0776ee37f5b45bfaea8cff1d8232fbb6122ec32",
"value" => "0x2a"
}
]
}
%Block{
height: 42,
hash: "0xc71303ef8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238",
transactions: [
%Transaction{
from: "hxbe258ceb872e08851f1f59694dac2558708ece11",
to: "cxb0776ee37f5b45bfaea8cff1d8232fbb6122ec32",
value: 42
}
]
} =
Block
|> Icon.Schema.generate()
|> Icon.Schema.new(payload)
|> Icon.Schema.load()
|> Icon.Schema.apply(into: Block)
Link to this section Summary
Functions
Schema state.
Uses the schema behaviour.
Generates a union of types.
Applies schema state
.
Generates a schema and its struct.
Dumps data from a schema state.
Generates an enum type.
Generates a full type_or_schema
, given a schema definition. It caches the
generated schema, to avoid regenarating the same every time.
Generates a list of types.
Loads data from a schema state.
Generates a new schema state.
Link to this section Types
@type external_type() :: internal_type() | {:list, external_type()} | {:any, [{atom(), external_type()}], atom()} | {:enum, [atom()]} | :address | :any | :binary_data | :boolean | :eoa_address | :error | :event_log | :hash | :integer | :loop | :pos_integer | :score_address | :signature | :string | :timestamp
External types.
@type internal_type() :: {:list, internal_type()} | {:any, [{atom(), internal_type()}], atom()} | {:enum, [atom()]} | t() | Icon.Schema.Error | Icon.Schema.Types.Address | Icon.Schema.Types.Any | Icon.Schema.Types.BinaryData | Icon.Schema.Types.Boolean | Icon.Schema.Types.EOA | Icon.Schema.Types.EventLog | Icon.Schema.Types.Hash | Icon.Schema.Types.Integer | Icon.Schema.Types.Loop | Icon.Schema.Types.PosInteger | Icon.Schema.Types.SCORE | Icon.Schema.Types.Signature | Icon.Schema.Types.String | Icon.Schema.Types.Timestamp | module()
Internal types.
@type state() :: %Icon.Schema{ data: map(), errors: map(), is_valid?: boolean(), params: map(), schema: t() }
Schema state.
Schema.
@type type() :: external_type() | {external_type(), keyword()}
Type.
Link to this section Callbacks
@callback init() :: t()
Callback for defining a schema.
Link to this section Functions
Schema state.
Uses the schema behaviour.
@spec any([{atom(), external_type()}], atom()) :: {:any, [{atom(), external_type()}], atom()}
Generates a union of types.
@spec apply( state(), keyword() ) :: {:ok, any()} | {:error, Icon.Schema.Error.t()}
Applies schema state
.
Generates a schema and its struct.
Dumps data from a schema state.
Generates an enum type.
Generates a full type_or_schema
, given a schema definition. It caches the
generated schema, to avoid regenarating the same every time.
@spec list(external_type()) :: {:list, external_type()}
Generates a list of types.
Loads data from a schema state.
Generates a new schema state.