Page MenuHomePhorge

No OneTemporary

Size
8 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/open_api_spex/operation2.ex b/lib/open_api_spex/operation2.ex
index ce0331f..54bb058 100644
--- a/lib/open_api_spex/operation2.ex
+++ b/lib/open_api_spex/operation2.ex
@@ -1,84 +1,83 @@
defmodule OpenApiSpex.Operation2 do
@moduledoc """
Defines the `OpenApiSpex.Operation.t` type.
"""
alias OpenApiSpex.{
Cast,
Operation,
Parameter,
RequestBody,
Schema
}
- alias Plug.Conn
-
alias OpenApiSpex.Cast.Error
+ alias Plug.Conn
@spec cast(Operation.t(), Conn.t(), String.t() | nil, Schema.schemas()) ::
{:error, [Error.t()]} | {:ok, Conn.t()}
def cast(operation = %Operation{}, conn = %Conn{}, content_type, schemas) do
- with {:ok, conn} <- cast_query_parameters(conn, operation, schemas),
+ with {:ok, conn} <- cast_parameters(conn, operation, schemas),
{:ok, body} <-
cast_request_body(operation.requestBody, conn.body_params, content_type, schemas) do
{:ok, %{conn | body_params: body}}
end
end
## Private functions
- defp cast_query_parameters(conn, operation, schemas) do
+ defp cast_parameters(conn, operation, schemas) do
parameters =
Enum.filter(operation.parameters || [], fn p ->
Map.has_key?(conn.params, Atom.to_string(p.name))
end)
with :ok <- check_query_params_defined(conn, operation.parameters),
- {:ok, parameter_values} <- cast_parameters(parameters, conn.params, schemas) do
+ {:ok, parameter_values} <- cast_known_parameters(parameters, conn.params, schemas) do
{:ok, %{conn | params: parameter_values}}
end
end
defp check_query_params_defined(%Conn{}, nil = _defined_params) do
:ok
end
defp check_query_params_defined(%Conn{} = conn, defined_params)
when is_list(defined_params) do
defined_query_params =
for param <- defined_params,
param.in == :query,
into: MapSet.new(),
do: to_string(param.name)
case validate_parameter_keys(Map.keys(conn.query_params), defined_query_params) do
{:error, name} -> {:error, [%Error{reason: :unexpected_field, name: name}]}
:ok -> :ok
end
end
defp validate_parameter_keys([], _defined_params), do: :ok
defp validate_parameter_keys([name | params], defined_params) do
case MapSet.member?(defined_params, name) do
false -> {:error, name}
_ -> validate_parameter_keys(params, defined_params)
end
end
- defp cast_parameters([], _params, _schemas), do: {:ok, %{}}
+ defp cast_known_parameters([], _params, _schemas), do: {:ok, %{}}
- defp cast_parameters([p | rest], params = %{}, schemas) do
+ defp cast_known_parameters([p | rest], params = %{}, schemas) do
with {:ok, cast_val} <-
Cast.cast(Parameter.schema(p), params[Atom.to_string(p.name)], schemas),
- {:ok, cast_tail} <- cast_parameters(rest, params, schemas) do
+ {:ok, cast_tail} <- cast_known_parameters(rest, params, schemas) do
{:ok, Map.put_new(cast_tail, p.name, cast_val)}
end
end
defp cast_request_body(nil, _, _, _), do: {:ok, %{}}
defp cast_request_body(%RequestBody{content: content}, params, content_type, schemas) do
schema = content[content_type].schema
Cast.cast(schema, params, schemas)
end
end
diff --git a/test/operation2_test.exs b/test/operation2_test.exs
index 729e263..588a2f9 100644
--- a/test/operation2_test.exs
+++ b/test/operation2_test.exs
@@ -1,145 +1,157 @@
defmodule OpenApiSpex.Operation2Test do
use ExUnit.Case
alias OpenApiSpex.{Operation, Operation2, Schema}
alias OpenApiSpex.Cast.Error
defmodule SchemaFixtures do
@user %Schema{
type: :object,
properties: %{
user: %Schema{
type: :object,
properties: %{
email: %Schema{type: :string}
}
}
}
}
@user_list %Schema{
type: :array,
items: @user
}
@schemas %{"User" => @user, "UserList" => @user_list}
def user, do: @user
def user_list, do: @user_list
def schemas, do: @schemas
end
defmodule OperationFixtures do
@user_index %Operation{
operationId: "UserController.index",
parameters: [
- Operation.parameter(:name, :query, :string, "Filter by user name")
+ Operation.parameter(:name, :query, :string, "Filter by user name"),
+ Operation.parameter(:age, :query, :integer, "User's age")
],
responses: %{
200 => Operation.response("User", "application/json", SchemaFixtures.user())
}
}
def user_index, do: @user_index
@create_user %Operation{
operationId: "UserController.create",
requestBody:
Operation.request_body("request body", "application/json", SchemaFixtures.user(),
required: true
),
responses: %{
200 => Operation.response("User list", "application/json", SchemaFixtures.user_list())
}
}
def create_user, do: @create_user
end
defmodule SpecModule do
def spec do
paths = %{
"/users" => %{
"post" => OperationFixtures.create_user()
}
}
%OpenApiSpex.OpenApi{
info: nil,
paths: paths,
components: %{
schemas: SchemaFixtures.schemas()
}
}
end
end
defmodule RenderError do
def init(_) do
nil
end
def call(_conn, _errors) do
raise "should not have errors"
end
end
describe "cast/4" do
test "cast request body" do
conn = create_conn(%{"user" => %{"email" => "foo@bar.com"}})
assert {:ok, conn} =
Operation2.cast(
OperationFixtures.create_user(),
conn,
"application/json",
SchemaFixtures.schemas()
)
assert %Plug.Conn{} = conn
end
- test "cast request body - validation error" do
+ test "cast request body - invalid data type" do
conn = create_conn(%{"user" => %{"email" => 123}})
assert {:error, errors} =
Operation2.cast(
OperationFixtures.create_user(),
conn,
"application/json",
SchemaFixtures.schemas()
)
assert [error] = errors
assert %Error{} = error
assert error.reason == :invalid_type
end
- test "validate param name is defined" do
+ test "validate undefined query param name" do
query_params = %{"unknown" => "asdf"}
- conn =
- :get
- |> Plug.Test.conn("/api/users")
- |> Plug.Conn.put_req_header("content-type", "application/json")
- |> Map.put(:query_params, query_params)
-
- assert {:error, errors} =
- Operation2.cast(
- OperationFixtures.user_index(),
- conn,
- "application/json",
- SchemaFixtures.schemas()
- )
+ assert {:error, [error]} = do_index_cast(query_params)
- assert [error] = errors
assert %Error{} = error
assert error.reason == :unexpected_field
assert error.name == "unknown"
end
+ test "validate invalid data type for query param" do
+ query_params = %{"age" => "asdf"}
+ assert {:error, [error]} = do_index_cast(query_params)
+ assert %Error{} = error
+ assert error.reason == :invalid_type
+ assert error.type == :integer
+ assert error.value == "asdf"
+ end
+
+ defp do_index_cast(query_params) do
+ conn =
+ :get
+ |> Plug.Test.conn("/api/users?" <> URI.encode_query(query_params))
+ |> Plug.Conn.put_req_header("content-type", "application/json")
+ |> Plug.Conn.fetch_query_params()
+
+ Operation2.cast(
+ OperationFixtures.user_index(),
+ conn,
+ "application/json",
+ SchemaFixtures.schemas()
+ )
+ end
+
defp create_conn(body_params) do
:post
|> Plug.Test.conn("/api/users")
|> Plug.Conn.put_req_header("content-type", "application/json")
|> Map.put(:body_params, body_params)
end
end
end

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 30, 3:56 PM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41493
Default Alt Text
(8 KB)

Event Timeline