Packages
eview
0.10.7
0.16.0
retired
0.15.0
0.14.0
0.13.0
0.12.5
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
0.11.1
0.11.0
0.10.8
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.0
0.5.2
0.5.1
0.5.0
0.4.0
0.3.0
0.2.9
0.2.7
0.2.6
0.2.5
0.2.3
0.2.2
0.2.1
0.2.0
0.1.1
0.1.0
Plug that converts response to Nebo #15 API spec format.
Current section
Files
Jump to
Current section
Files
lib/eview/changeset/validators/metadata_validator.ex
if Code.ensure_loaded?(Ecto) do
defmodule EView.Changeset.Validators.Metadata do
@moduledoc """
This helper validates metadata corresponding to
[API Manifest](http://docs.apimanifest.apiary.io/#introduction/optional-features/metadata).
"""
import Ecto.Changeset
@max_key_length 100
@max_value_length 500
@max_list_length 25
@max_list_value_length 100
@jsonpath_joiner "."
def validate_metadata(changeset, field, opts \\ []) do
validate_change changeset, field, :metadata, fn _, value ->
get_metadata_errors(field, value, opts)
end
end
defp get_metadata_errors(field, metadata, _opts) when is_map(metadata) do
Enum.reduce(metadata, [], &field_validation_reducer(field, &1, &2))
end
defp get_metadata_errors(field, _, opts) do
[{field, {message(opts, "is not a valid metadata object"), [validation: :metadata]}}]
end
# Convert atom keys to strings
defp field_validation_reducer(parent, {key, val}, acc) when is_atom(key) do
field_validation_reducer(parent, {to_string(key), val}, acc)
end
# Check max length of key
defp field_validation_reducer(parent, {key, _}, acc) when is_binary(key) and byte_size(key) > @max_key_length do
[{field_path(parent, key),
{"key should be up to %{max} characters", [validation: :length, max: @max_key_length]}}
| acc]
end
# Check binary value max length
defp field_validation_reducer(parent, {key, val}, acc) when is_binary(val) and byte_size(val) > @max_value_length do
[{field_path(parent, key),
{"value should be up to %{max} characters", [validation: :length, max: @max_value_length]}}
| acc]
end
# Check list values
defp field_validation_reducer(parent, {key, list}, acc) when is_list(list) and length(list) > @max_list_length do
[{field_path(parent, key),
{"lists should be up to %{max} elements", [validation: :length, max: @max_list_length]}}
| acc]
end
# Check list elements length
defp field_validation_reducer(parent, {key, list}, acc) when is_list(list) do
{errors, _} = Enum.reduce(list, {[], 0}, fn
%Decimal{}, {el_acc, i} ->
{el_acc, i + 1}
elem, {el_acc, i} when is_float(elem) or is_number(elem) ->
{el_acc, i + 1}
elem, {el_acc, i} when is_binary(elem) and byte_size(elem) <= @max_list_value_length ->
{el_acc, i + 1}
elem, {el_acc, i} when is_binary(elem) and byte_size(elem) > @max_list_value_length ->
{[{join_atoms(field_path(parent, key), "[#{i}]"),
{"list keys should be up to %{max} characters", [validation: :length, max: @max_key_length]}}
| el_acc], i + 1}
_, {el_acc, i} ->
{[{field_path(parent, key),
{"one of keys is invalid", [validation: :cast, type: [:integer, :float, :decimal, :string]]}}
| el_acc], i + 1}
end)
errors ++ acc
end
# Pass integers, decimals and floats
defp field_validation_reducer(_parent, {_, number}, acc) when is_float(number) or is_integer(number), do: acc
defp field_validation_reducer(_parent, {_, %Decimal{}}, acc), do: acc
# Pass valid binary keys and values
defp field_validation_reducer(_parent, {key, val}, acc)
when is_binary(key) and byte_size(key) <= @max_key_length
and is_binary(val) and byte_size(val) <= @max_value_length do
acc
end
# Everything else is an error
defp field_validation_reducer(parent, {key, _val}, acc) do
[{field_path(parent, key),
{"is invalid", [validation: :cast, type: [:integer, :float, :decimal, :string]]}}
| acc]
end
# Join atom in JSON Path style
defp field_path(parent, child) do
String.to_atom(to_string(parent) <> @jsonpath_joiner <> to_string(child))
end
# Join strings or atoms and return a string
defp join_atoms(prefix, sufix) do
String.to_atom(to_string(prefix) <> to_string(sufix))
end
# Extract message from options
defp message(opts, key \\ :message, default) do
Keyword.get(opts, key, default)
end
end
end