-
Notifications
You must be signed in to change notification settings - Fork 103
Expand file tree
/
Copy pathvalidator.ex
More file actions
164 lines (140 loc) · 6.16 KB
/
validator.ex
File metadata and controls
164 lines (140 loc) · 6.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
defmodule ExJsonSchema.Validator do
alias ExJsonSchema.Validator.Error
alias ExJsonSchema.Schema
alias ExJsonSchema.Schema.Root
@type errors :: [%Error{}] | list
@type options :: [error_formatter: module() | false]
@callback validate(
Root.t(),
ExJsonSchema.data(),
{String.t(), ExJsonSchema.data()},
ExJsonSchema.data(),
ExJsonSchema.json_path()
) :: errors
@spec validate(Root.t() | ExJsonSchema.object(), ExJsonSchema.data()) ::
:ok | {:error, errors} | no_return
def validate(root, data, options \\ [])
def validate(root = %Root{}, data, options) when is_list(options) do
validate_fragment(root, root.schema, data, options)
end
def validate(schema = %{}, data, options) when is_list(options) do
validate(Schema.resolve(schema), data, options)
end
@spec validate_fragment(
Root.t(),
ExJsonSchema.json_path() | Schema.resolved(),
ExJsonSchema.data(),
options
) :: :ok | {:error, errors} | Schema.invalid_reference_error() | no_return
def validate_fragment(root, schema_or_ref, data, options \\ []) when is_list(options) do
result =
case validation_errors(root, schema_or_ref, data) do
{:error, _error} = error -> error
[] -> :ok
errors -> {:error, errors}
end
case Keyword.get(options, :error_formatter, Error.StringFormatter) do
false -> result
formatter -> format_errors(result, formatter)
end
end
@spec validation_errors(
Root.t(),
ExJsonSchema.json_path() | Schema.resolved(),
ExJsonSchema.data(),
String.t()
) :: errors | Schema.invalid_reference_error() | no_return
def validation_errors(root, schema_or_ref, data, path \\ "#")
def validation_errors(root, ref, data, path) when is_binary(ref) do
case Schema.get_fragment(root, ref) do
{:ok, schema} -> validation_errors(root, schema, data, path)
error -> error
end
end
def validation_errors(root = %Root{}, %{"$ref" => ref}, data, path) do
do_validation_errors(root, %{"$ref" => ref}, data, path)
end
def validation_errors(%Root{}, true, _data, _path) do
[]
end
def validation_errors(%Root{}, false, _data, path) do
[%Error{error: %Error.False{}, path: path}]
end
def validation_errors(root = %Root{}, schema = %{}, data, path) do
do_validation_errors(root, schema, data, path)
end
def do_validation_errors(root = %Root{}, schema = %{}, data, path) do
schema
# TODO
# |> Map.put_new("nullable", false)
|> Enum.flat_map(fn {propertyName, _} = property ->
case validator_for(propertyName) do
nil -> []
validator -> validator.validate(root, schema, property, data, path)
end
end)
|> Enum.map(fn
%Error{path: nil} = error -> %{error | path: path}
error -> error
end)
end
@spec valid?(Root.t() | ExJsonSchema.object(), ExJsonSchema.data()) :: boolean | no_return
def valid?(root = %Root{}, data), do: valid_fragment?(root, root.schema, data)
def valid?(schema = %{}, data), do: valid?(Schema.resolve(schema), data)
@spec valid_fragment?(
Root.t(),
ExJsonSchema.json_path() | Schema.resolved(),
ExJsonSchema.data()
) :: boolean | Schema.invalid_reference_error() | no_return
def valid_fragment?(root, schema_or_ref, data) do
case validation_errors(root, schema_or_ref, data) do
{:error, _error} = error -> error
[] -> true
_errors -> false
end
end
def map_to_invalid_errors(errors_with_index) do
errors_with_index
|> Enum.map(fn {errors, index} ->
%Error.InvalidAtIndex{errors: errors, index: index}
end)
end
defp format_errors(:ok, _error_formatter), do: :ok
defp format_errors({:error, errors}, error_formatter) when is_list(errors) do
{:error, error_formatter.format(errors)}
end
defp format_errors({:error, _} = error, _error_formatter), do: error
defp validator_for("allOf"), do: ExJsonSchema.Validator.AllOf
defp validator_for("anyOf"), do: ExJsonSchema.Validator.AnyOf
defp validator_for("const"), do: ExJsonSchema.Validator.Const
defp validator_for("contains"), do: ExJsonSchema.Validator.Contains
defp validator_for("contentEncoding"),
do: ExJsonSchema.Validator.ContentEncodingContentMediaType
defp validator_for("dependencies"), do: ExJsonSchema.Validator.Dependencies
defp validator_for("enum"), do: ExJsonSchema.Validator.Enum
defp validator_for("exclusiveMaximum"), do: ExJsonSchema.Validator.ExclusiveMaximum
defp validator_for("exclusiveMinimum"), do: ExJsonSchema.Validator.ExclusiveMinimum
defp validator_for("format"), do: ExJsonSchema.Validator.Format
defp validator_for("if"), do: ExJsonSchema.Validator.IfThenElse
defp validator_for("items"), do: ExJsonSchema.Validator.Items
defp validator_for("maxItems"), do: ExJsonSchema.Validator.MaxItems
defp validator_for("maxLength"), do: ExJsonSchema.Validator.MaxLength
defp validator_for("maxProperties"), do: ExJsonSchema.Validator.MaxProperties
defp validator_for("maximum"), do: ExJsonSchema.Validator.Maximum
defp validator_for("minItems"), do: ExJsonSchema.Validator.MinItems
defp validator_for("minLength"), do: ExJsonSchema.Validator.MinLength
defp validator_for("minProperties"), do: ExJsonSchema.Validator.MinProperties
defp validator_for("minimum"), do: ExJsonSchema.Validator.Minimum
defp validator_for("multipleOf"), do: ExJsonSchema.Validator.MultipleOf
defp validator_for("not"), do: ExJsonSchema.Validator.Not
defp validator_for("oneOf"), do: ExJsonSchema.Validator.OneOf
defp validator_for("pattern"), do: ExJsonSchema.Validator.Pattern
defp validator_for("properties"), do: ExJsonSchema.Validator.Properties
defp validator_for("propertyNames"), do: ExJsonSchema.Validator.PropertyNames
defp validator_for("$ref"), do: ExJsonSchema.Validator.Ref
defp validator_for("required"), do: ExJsonSchema.Validator.Required
defp validator_for("type"), do: ExJsonSchema.Validator.Type
defp validator_for("nullable"), do: ExJsonSchema.Validator.Nullable
defp validator_for("uniqueItems"), do: ExJsonSchema.Validator.UniqueItems
defp validator_for(_), do: nil
end