Configure a loader
A loader returns the data for a remote schema. The remote schemas are defined in a schema like this.
...
properties: %{
int: {:ref, "http://localhost:1234/int.exon"}
}
...
A loader will be configured like this.
config :xema, loader: My.Loader
A loader is a module which use the behaviour Xema.Loader
.
defmodule My.Loader do
@moduledoc false
@behaviour Xema.Loader
@spec fetch(binary) :: {:ok, map} | {:error, any}
def fetch(uri) do
with {:ok, response} <- get(uri), do: eval(response, uri)
end
defp get(uri) do
case HTTPoison.get(uri) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
{:ok, body}
{:ok, %HTTPoison.Response{status_code: 404}} ->
{:error, "Remote schema '#{uri}' not found."}
{:ok, %HTTPoison.Response{status_code: code}} ->
{:error, "code: #{code}"}
{:error, reason} ->
{:error, reason}
end
end
defp eval(str, uri) do
{data, _} = Code.eval_string(str)
{:ok, data}
rescue
error -> {:error, %{error | file: URI.to_string(uri)}}
end
end
The function fetch/1
will be called by Xema
and expects an %URI{}
. The
return value must be a tuple of :ok
and the required data for a schema or an
error tuple.
Note! This loader use Code.eval_string/1
and eval is always evil.
Warning: string can be any Elixir code and will be executed with the same privileges as the Erlang VM: this means that such code could compromise the machine (for example by executing system commands). Don’t use
eval_string/3
with untrusted input (such as strings coming from the network). -- Elixir API
File loader
A loader to read schema from the local file system.
In the schema:
...
properties: %{
int: {:ref, "int.exon"}
}
...
The loader:
defmodule My.Loader do
@moduledoc false
@behaviour Xema.Loader
@spec fetch(binary) :: {:ok, map} | {:error, any}
def fetch(uri) do
"path/to/schemas"
|> Path.join(uri.path)
|> File.read!()
|> eval(uri)
end
defp eval(str, uri) do
{data, _} = Code.eval_string(str)
{:ok, data}
rescue
error -> {:error, %{error | file: URI.to_string(uri)}}
end
end
JSON Schema loader
If the scheme is created with Xema.from_json_schema/2
, the loader must return
the decoded JSON.
In this case the file loader looks like this:
defmodule My.Loader do
@moduledoc false
@behaviour Xema.Loader
@spec fetch(binary) :: {:ok, map} | {:error, any}
def fetch(uri) do
"path/to/schemas"
|> Path.join(uri.path)
|> File.read!()
|> Jason.decode()
end
end