Skip to content

Commit

Permalink
Support custom error messages in custom validators (#621)
Browse files Browse the repository at this point in the history
* Add custom message for custom validators
  • Loading branch information
GregorGrasselli authored Jul 16, 2024
1 parent c90e46e commit 19ffc49
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 0 deletions.
12 changes: 12 additions & 0 deletions lib/open_api_spex/cast/error.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ defmodule OpenApiSpex.Cast.Error do
@type one_of_error :: {:one_of, [String.t()]}
@type unexpected_field_error :: {:unexpected_field, String.t() | atom()}
@type unique_items_error :: {:unique_items}
@type custom_error :: {:custom, String.t()}

@type reason ::
:all_of
Expand Down Expand Up @@ -56,6 +57,7 @@ defmodule OpenApiSpex.Cast.Error do
| :one_of
| :unexpected_field
| :unique_items
| :custom

@type args ::
all_of_error()
Expand Down Expand Up @@ -84,6 +86,7 @@ defmodule OpenApiSpex.Cast.Error do
| one_of_error()
| unexpected_field_error()
| unique_items_error()
| custom_error()

@type t :: %__MODULE__{
reason: reason(),
Expand Down Expand Up @@ -244,6 +247,11 @@ defmodule OpenApiSpex.Cast.Error do
|> add_context_fields(ctx)
end

def new(ctx, {:custom, message}) do
%__MODULE__{reason: :custom, meta: %{message: message}}
|> add_context_fields(ctx)
end

@spec message(t()) :: String.t()

def message(%{reason: :invalid_schema_type, type: type}) do
Expand Down Expand Up @@ -365,6 +373,10 @@ defmodule OpenApiSpex.Cast.Error do
"Object property count #{meta.property_count} is less than minProperties: #{meta.min_properties}"
end

def message(%{reason: :custom, meta: meta}) do
meta.message
end

def message_with_path(error) do
prepend_path(error, message(error))
end
Expand Down
28 changes: 28 additions & 0 deletions test/cast_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,34 @@ defmodule OpenApiSpec.CastTest do
assert Error.message_with_path(error) == "#/age: Invalid strict_integer. Got: string"
end

test "cast custom error with custom validator" do
defmodule EvenInt do
require OpenApiSpex

alias OpenApiSpex.Cast

OpenApiSpex.schema(%{
description: "An even integer",
type: :integer,
"x-validate": __MODULE__
})

def cast(context = %Cast{value: value}) when is_integer(value) and rem(value, 2) == 0,
do: Cast.ok(context)

def cast(context), do: Cast.error(context, {:custom, "Must be an even integer"})
end

schema = %Schema{type: :object, properties: %{even_number: EvenInt.schema()}}

assert {:error, errors} = cast(value: %{"even_number" => 1}, schema: schema)
assert [error] = errors
assert %Error{} = error
assert error.reason == :custom
assert error.path == [:even_number]
assert Error.message_with_path(error) == "#/even_number: Must be an even integer"
end

test "nil value with xxxOf" do
schema = %Schema{anyOf: [%Schema{nullable: true, type: :string}]}
assert {:ok, nil} = cast(value: nil, schema: schema)
Expand Down

0 comments on commit 19ffc49

Please sign in to comment.