Skip to content

Commit

Permalink
Merge pull request #87 from botsquad/custom-format-validator-fn
Browse files Browse the repository at this point in the history
Support anonymous functions as custom validator function
  • Loading branch information
jonasschmidt committed Nov 15, 2023
2 parents 7d7015c + bf8e4dd commit 9a4aa62
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 5 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,14 @@ ExJsonSchema.Schema.resolve(%{"format" => "custom"}, custom_format_validator: {M

The configured function is called with the arguments `(format, data)` and is expected to return `true`, `false` or a `{:error, %Error.Format{expected: "something"}}` tuple, 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.

The custom function can also be an anonymous function:

```elixir
ExJsonSchema.Schema.resolve(%{"format" => "custom"}, custom_format_validator: fn format, data -> true end)
```

> Note that the anonymous function version of the custom validator is only available in the option to Schema.resolve/2 and not as Application config, as using anonymous functions as configuration is not allowed.
[format-spec]: https://json-schema.org/understanding-json-schema/reference/string.html#format

## License
Expand All @@ -180,5 +188,5 @@ Released under the [MIT license](https://github.com/jonasschmidt/ex_json_schema/

## TODO

* Add some source code documentation
* Enable providing JSON for known schemata at resolve time
- Add some source code documentation
- Enable providing JSON for known schemata at resolve time
2 changes: 1 addition & 1 deletion lib/ex_json_schema/schema/root.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ defmodule ExJsonSchema.Schema.Root do
location: :root | String.t(),
definitions: %{String.t() => ExJsonSchema.Schema.resolved()},
version: non_neg_integer | nil,
custom_format_validator: {module(), atom()} | nil
custom_format_validator: {module(), atom()} | (String.t(), any() -> boolean | {:error, any()}) | nil
}
end
12 changes: 10 additions & 2 deletions lib/ex_json_schema/validator/format.ex
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,16 @@ defmodule ExJsonSchema.Validator.Format do
validate_with_custom_validator(validator, format, data)
end

defp validate_with_custom_validator({mod, fun}, format, data) do
case apply(mod, fun, [format, data]) do
defp do_validate(%Root{custom_format_validator: validator}, format, data) when is_function(validator) do
validate_with_custom_validator(validator, format, data)
end

defp validate_with_custom_validator(validator, format, data) do
result = case validator do
{mod, fun} -> apply(mod, fun, [format, data])
fun when is_function(fun, 2) -> fun.(format, data)
end
case result do
true -> []
false -> [%Error{error: %Error.Format{expected: format}}]
{:error, error} -> [%Error{error: error}]
Expand Down
25 changes: 25 additions & 0 deletions test/ex_json_schema/validator_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,31 @@ defmodule ExJsonSchema.ValidatorTest do
)
end

test "configuring an anonymous function as custom format validator" do
anonymous_validation_fn = fn "myformat", data ->
data == "mydata"
end

schema =
Schema.resolve(
%{
"properties" => %{
"error" => %{"format" => "myformat"}
}
},
custom_format_validator: anonymous_validation_fn
)

assert :ok = validate(schema, %{"error" => "mydata"})

assert_validation_errors(
schema,
%{"error" => ""},
[{"Expected to be a valid myformat.", "#/error"}],
[%Error{error: %Error.Format{expected: "myformat"}, path: "#/error"}]
)
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 9a4aa62

Please sign in to comment.