Skip to content

Commit

Permalink
Merge pull request #51 from botsquad/custom-format-validator
Browse files Browse the repository at this point in the history
Implement the custom format validator
  • Loading branch information
jonasschmidt committed Sep 25, 2019
2 parents 134b61a + 9b9c758 commit 0d6e04f
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 2 deletions.
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

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

0 comments on commit 0d6e04f

Please sign in to comment.