Skip to content

Commit 620c57e

Browse files
GPrimolaGiorgio Torres
and
Giorgio Torres
authored
Fix cast x-validate when decoded schema (#647)
* Fix cast x-validate when decoded schema * fix credo complain when using apply/3 --------- Co-authored-by: Giorgio Torres <[email protected]>
1 parent 1447498 commit 620c57e

File tree

3 files changed

+48
-20
lines changed

3 files changed

+48
-20
lines changed

lib/open_api_spex/cast.ex

+6-2
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,12 @@ defmodule OpenApiSpex.Cast do
119119
@spec cast(t()) :: {:ok, term()} | {:error, [Error.t()]}
120120

121121
# Custom validator
122-
def cast(%__MODULE__{schema: %{"x-validate": module}} = ctx) when module != nil,
123-
do: module.cast(ctx)
122+
def cast(%__MODULE__{schema: %{"x-validate": module}} = ctx)
123+
when is_atom(module) and module != nil,
124+
do: module.cast(ctx)
125+
126+
def cast(%__MODULE__{schema: %{"x-validate": module}} = ctx) when is_binary(module),
127+
do: module |> Elixir.String.split(".") |> Module.concat() |> then(& &1.cast(ctx))
124128

125129
# nil schema
126130
def cast(%__MODULE__{value: value, schema: nil}),

test/cast_test.exs

+33-18
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@ defmodule OpenApiSpec.CastTest do
77
def cast(ctx), do: Cast.cast(ctx)
88

99
describe "cast/1" do
10+
defmodule CustomValidator.EvenInt do
11+
require OpenApiSpex
12+
13+
alias OpenApiSpex.Cast
14+
15+
OpenApiSpex.schema(%{
16+
description: "An even integer",
17+
type: :integer,
18+
"x-validate": __MODULE__
19+
})
20+
21+
def cast(context = %Cast{value: value}) when is_integer(value) and rem(value, 2) == 0,
22+
do: Cast.ok(context)
23+
24+
def cast(context), do: Cast.error(context, {:custom, "Must be an even integer"})
25+
end
26+
1027
test "unknown schema type" do
1128
assert {:error, [error]} = cast(value: "string", schema: %Schema{type: :nope})
1229
assert error.reason == :invalid_schema_type
@@ -223,24 +240,7 @@ defmodule OpenApiSpec.CastTest do
223240
end
224241

225242
test "cast custom error with custom validator" do
226-
defmodule EvenInt do
227-
require OpenApiSpex
228-
229-
alias OpenApiSpex.Cast
230-
231-
OpenApiSpex.schema(%{
232-
description: "An even integer",
233-
type: :integer,
234-
"x-validate": __MODULE__
235-
})
236-
237-
def cast(context = %Cast{value: value}) when is_integer(value) and rem(value, 2) == 0,
238-
do: Cast.ok(context)
239-
240-
def cast(context), do: Cast.error(context, {:custom, "Must be an even integer"})
241-
end
242-
243-
schema = %Schema{type: :object, properties: %{even_number: EvenInt.schema()}}
243+
schema = %Schema{type: :object, properties: %{even_number: CustomValidator.EvenInt.schema()}}
244244

245245
assert {:error, errors} = cast(value: %{"even_number" => 1}, schema: schema)
246246
assert [error] = errors
@@ -250,6 +250,21 @@ defmodule OpenApiSpec.CastTest do
250250
assert Error.message_with_path(error) == "#/even_number: Must be an even integer"
251251
end
252252

253+
test "cast with custom validator from decoded schema" do
254+
spec =
255+
"./test/support/encoded_schema.json"
256+
|> File.read!()
257+
|> Jason.decode!()
258+
|> OpenApiSpex.OpenApi.Decode.decode()
259+
260+
%{
261+
components: %{schemas: %{"CustomValidationDecoded" => custom_validation_schema}}
262+
} = spec
263+
264+
assert {:ok, %{even_num: 2}} =
265+
cast(value: %{"even_num" => 2}, schema: custom_validation_schema)
266+
end
267+
253268
test "nil value with xxxOf" do
254269
schema = %Schema{anyOf: [%Schema{nullable: true, type: :string}]}
255270
assert {:ok, nil} = cast(value: nil, schema: schema)

test/support/encoded_schema.json

+9
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,15 @@
280280
"not": {
281281
"type": "string"
282282
}
283+
},
284+
"CustomValidationDecoded": {
285+
"type": "object",
286+
"properties": {
287+
"even_num": {
288+
"type": "integer",
289+
"x-validate": "OpenApiSpec.CastTest.CustomValidator.EvenInt"
290+
}
291+
}
283292
}
284293
},
285294
"links": {

0 commit comments

Comments
 (0)