|
defmodule MyApp.Validator do |
|
@moduledoc_intro """ |
|
This module provides the ability to validate JSON payloads via JSON schema. |
|
|
|
All validations methods are generated based on the contents |
|
of priv/json_schemas. |
|
|
|
For each schema file, this module will generate two |
|
functions (`validate/2` and `schema_for/1`). |
|
|
|
So if you have a `priv/json_schemas/message-new.json` file, this |
|
module will create: |
|
|
|
- `validate("message-new", payload)` |
|
- `schema_for("message-new")` |
|
|
|
It's important to call these files with the same payload names used for events and actions |
|
in all channels. |
|
|
|
For more information about how this code is generated, see the following resources: |
|
|
|
- <http://elixir-lang.org/docs/stable/elixir/Kernel.SpecialForms.html#quote/2-binding-and-unquote-fragments> |
|
- <http://elixir-lang.org/docs/stable/elixir/Macro.html#escape/1> |
|
|
|
""" |
|
|
|
schema_files = :code.priv_dir(:my_app) |
|
|> List.to_string |
|
|> Path.join("json_schemas") |
|
|> Path.join("*.json") |
|
|> Path.wildcard |
|
|
|
@spec validate(String.t, ExJsonSchema.data) :: :ok | {:error, ExJsonSchema.Validator.errors} |
|
@spec schema_for(String.t) :: ExJsonSchema.data |
|
|
|
Module.register_attribute(__MODULE__, :schemas, accumulate: true) |
|
|
|
for file <- schema_files do |
|
@external_resource file |
|
|
|
file_name = Path.basename(file, ".json") |
|
content = file |
|
|> File.read! |
|
|> Poison.decode! |
|
|
|
Module.put_attribute(__MODULE__, :schemas, {file_name, content}) |
|
|
|
@doc """ |
|
Validate a map with string keys against a specific schema, identified |
|
by a payload name. |
|
""" |
|
def validate(unquote(file_name), payload) do |
|
unquote(file_name) |
|
|> schema_for |
|
|> ExJsonSchema.Validator.validate(payload) |
|
end |
|
|
|
@doc """ |
|
Returns the schema in map form for a given payload name |
|
|
|
#{file_name} |
|
""" |
|
def schema_for(unquote(file_name)), do: unquote(Macro.escape(content)) |
|
end |
|
|
|
moduledoc_template = """ |
|
<%= intro %> |
|
|
|
# Available schemas |
|
|
|
<%= for {file_name, content} <- schemas do %> |
|
|
|
## <%= file_name %> |
|
|
|
```json |
|
<%= Poison.encode!(content, pretty: true) %> |
|
``` |
|
|
|
<%= end %> |
|
""" |
|
|
|
rendered = EEx.eval_string(moduledoc_template, intro: @moduledoc_intro, |
|
schemas: Module.get_attribute(__MODULE__, :schemas)) |
|
|
|
@moduledoc rendered |
|
end |