Page MenuHomePhorge

No OneTemporary

Size
5 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/open_api_spex/cast_object.ex b/lib/open_api_spex/cast_object.ex
index 250440f..ab2ea53 100644
--- a/lib/open_api_spex/cast_object.ex
+++ b/lib/open_api_spex/cast_object.ex
@@ -1,41 +1,56 @@
defmodule OpenApiSpex.CastObject do
@moduledoc false
alias OpenApiSpex.Error
def cast(value, schema, schemas \\ %{})
def cast(value, %{properties: nil}, _schemas) do
{:ok, value}
end
def cast(value, schema, _schemas) do
- with :ok <- check_unrecognized_properties(value, schema.properties) do
- {:ok, cast_atom_keys(value, schema.properties)}
+ with :ok <- check_unrecognized_properties(value, schema.properties),
+ value <- cast_atom_keys(value, schema.properties),
+ :ok <- check_required_fields(value, schema) do
+ {:ok, value}
end
end
defp check_unrecognized_properties(value, expected_keys) do
input_keys = value |> Map.keys() |> Enum.map(&to_string/1)
schema_keys = expected_keys |> Map.keys() |> Enum.map(&to_string/1)
extra_keys = input_keys -- schema_keys
if extra_keys == [] do
:ok
else
[name | _] = extra_keys
{:error, Error.new(:unexpected_field, name)}
end
end
+ defp check_required_fields(input_map, schema) do
+ required = schema.required || []
+ input_keys = Map.keys(input_map)
+ missing_keys = required -- input_keys
+
+ if missing_keys == [] do
+ :ok
+ else
+ [key | _] = missing_keys
+ {:error, Error.new(:missing_field, key)}
+ end
+ end
+
defp cast_atom_keys(input_map, properties) do
Enum.reduce(properties, %{}, fn {key, _}, output ->
string_key = to_string(key)
case input_map do
%{^key => value} -> Map.put(output, key, value)
%{^string_key => value} -> Map.put(output, key, value)
_ -> output
end
end)
end
end
diff --git a/lib/open_api_spex/error.ex b/lib/open_api_spex/error.ex
index 8d65999..fe8b929 100644
--- a/lib/open_api_spex/error.ex
+++ b/lib/open_api_spex/error.ex
@@ -1,58 +1,66 @@
defmodule OpenApiSpex.Error do
defstruct reason: nil,
value: nil,
format: nil,
type: nil,
name: nil,
path: []
def new(:invalid_type, type, value) do
%__MODULE__{reason: :invalid_type, type: type, value: value}
end
def new(:polymorphic_failed, value, polymorphic_type) do
%__MODULE__{reason: :polymorphic_failed, value: value, type: polymorphic_type}
end
def new(:invalid_format, format, value) do
%__MODULE__{reason: :invalid_format, format: format, value: value}
end
def new(:unexpected_field, name) do
%__MODULE__{reason: :unexpected_field, name: name}
end
+ def new(:missing_field, name) do
+ %__MODULE__{reason: :missing_field, name: name}
+ end
+
def new(:no_value_required_for_discriminator, property_name) do
%__MODULE__{reason: :no_value_required_for_discriminator, name: property_name}
end
def new(:unknown_schema, name) do
%__MODULE__{reason: :unknown_schema, name: name}
end
def message(%{reason: :invalid_type, type: type, value: value}) do
"Invalid #{type}: #{inspect(value)}"
end
def message(%{reason: :polymorphic_failed, type: polymorphic_type}) do
"Failed to cast to any schema in #{polymorphic_type}"
end
def message(%{reason: :unexpected_field, value: value}) do
"Unexpected field with value #{inspect(value)}"
end
def message(%{reason: :no_value_required_for_discriminator, name: field}) do
"No value for required disciminator property: #{field}"
end
def message(%{reason: :unknown_schema, name: name}) do
"Unknown schema: #{name}"
end
+
+ def message(%{reason: :missing_field, name: name}) do
+ "Missing field: #{name}"
+ end
end
defimpl String.Chars, for: OpenApiSpex.Error do
def to_string(error) do
OpenApiSpex.Error.message(error)
end
end
diff --git a/test/cast_object_test.exs b/test/cast_object_test.exs
index 5c98400..5b0bf8f 100644
--- a/test/cast_object_test.exs
+++ b/test/cast_object_test.exs
@@ -1,30 +1,43 @@
defmodule OpenApiSpex.CastObjectTest do
use ExUnit.Case
import OpenApiSpex.CastObject
alias OpenApiSpex.{Error, Schema}
describe "cast/3" do
test "properties:nil, given unknown input property" do
schema = %Schema{type: :object}
assert cast(%{}, schema) == {:ok, %{}}
assert cast(%{"unknown" => "hello"}, schema) == {:ok, %{"unknown" => "hello"}}
end
test "with empty schema properties, given unknown input property" do
schema = %Schema{type: :object, properties: %{}}
assert cast(%{}, schema) == {:ok, %{}}
assert {:error, error} = cast(%{"unknown" => "hello"}, schema)
assert %Error{} = error
end
test "with schema properties set, given known input property" do
schema = %Schema{
type: :object,
properties: %{age: nil}
}
assert cast(%{}, schema) == {:ok, %{}}
assert cast(%{"age" => "hello"}, schema) == {:ok, %{age: "hello"}}
end
+
+ test "required fields" do
+ schema = %Schema{
+ type: :object,
+ properties: %{age: nil},
+ required: [:age]
+ }
+
+ assert {:error, error} = cast(%{}, schema)
+ assert %Error{} = error
+ assert error.reason == :missing_field
+ assert error.name == :age
+ end
end
end

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 30, 5:34 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41504
Default Alt Text
(5 KB)

Event Timeline