Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the custom format validator #51

Merged
merged 3 commits into from
Sep 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@ true

The validator supports all the formats specified by draft 4 (`date-time`, `email`, `hostname`, `ipv4`, `ipv6`), with the exception of the `uri` format which has confusing/broken requirements in the official test suite (see https://github.com/json-schema/JSON-Schema-Test-Suite/issues/77).

### Custom formats

The [JSON schema spec][format-spec] states that the `format` property "allows values to be constrained beyond what the other tools in JSON Schema can do". To support this, you can configure a callback validator function which gets called when a `format` property is encountered that is not one of the builtin formats:

```elixir
config :ex_json_schema,
:custom_format_validator,
{MyModule, :my_validator}
```

The configured function is called with the arguments `(format, data)` and is expected to return either `true` or `false`, depending whether the data is valid for the given format. For compatibility with JSON schema, it is expected to return `true` when the format is unknown by your callback function.

[format-spec]: https://json-schema.org/understanding-json-schema/reference/string.html#format


## License

Released under the [MIT license](LICENSE).
Expand Down
13 changes: 11 additions & 2 deletions lib/ex_json_schema/validator/format.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,16 @@ defmodule ExJsonSchema.Validator.Format do
end
end

defp do_validate(_, _) do
[]
defp do_validate(format, data) do
case Application.fetch_env(:ex_json_schema, :custom_format_validator) do
:error ->
[]

{:ok, {mod, fun}} ->
case apply(mod, fun, [format, data]) do
true -> []
false -> [%Error{error: %Error.Format{expected: format}, path: ""}]
end
end
end
end
42 changes: 42 additions & 0 deletions test/ex_json_schema/validator_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,48 @@ defmodule ExJsonSchema.ValidatorTest do
)
end

test "unknown formats are ignored" do
assert :ok == validate(%{"format" => "custom-format"}, "asdfsadf")
end

defmodule MyFormatValidator do
def validate_format("always_error", _data) do
false
end

def validate_format("zipcode", data) do
Regex.match?(~r/^\d+$/, data)
end
end
jonasschmidt marked this conversation as resolved.
Show resolved Hide resolved

test "configuring a custom formatter" do
Application.put_env(
:ex_json_schema,
:custom_format_validator,
{MyFormatValidator, :validate_format}
)

on_exit(fn ->
Application.delete_env(:ex_json_schema, :custom_format_validator)
end)

assert_validation_errors(
%{"format" => "always_error"},
"",
[{"Expected to be a valid always_error.", "#"}],
[%Error{error: %Error.Format{expected: "always_error"}, path: "#"}]
)

assert :ok == validate(%{"format" => "zipcode"}, "12345")

assert_validation_errors(
%{"format" => "zipcode"},
"asdf",
[{"Expected to be a valid zipcode.", "#"}],
[%Error{error: %Error.Format{expected: "zipcode"}, path: "#"}]
)
end

test "passing the formatter as an option" do
assert :ok = validate(%{"type" => "string"}, "foo", error_formatter: Error.StringFormatter)

Expand Down