Page MenuHomePhorge

No OneTemporary

Size
6 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/open_api_spex/cast_parameters.ex b/lib/open_api_spex/cast_parameters.ex
index 1a491d5..746df7e 100644
--- a/lib/open_api_spex/cast_parameters.ex
+++ b/lib/open_api_spex/cast_parameters.ex
@@ -1,100 +1,105 @@
defmodule OpenApiSpex.CastParameters do
@moduledoc false
alias OpenApiSpex.{Cast, Operation, Parameter, Schema, Reference, Components}
alias OpenApiSpex.Cast.{Error, Object}
alias Plug.Conn
@spec cast(Plug.Conn.t(), Operation.t(), Components.t()) ::
{:error, [Error.t()]} | {:ok, Conn.t()}
def cast(conn, operation, components) do
full_cast_result =
schemas_by_location(operation, components)
|> Enum.map(fn {location, schema} -> cast_location(location, schema, components, conn) end)
|> reduce_cast_results()
case full_cast_result do
{:ok, params} -> {:ok, %{conn | params: params}}
err -> err
end
end
defp get_params_by_location(conn, :query, _) do
Plug.Conn.fetch_query_params(conn).query_params
end
defp get_params_by_location(conn, :path, _) do
conn.path_params
end
defp get_params_by_location(conn, :cookie, _) do
Plug.Conn.fetch_cookies(conn).req_cookies
end
defp get_params_by_location(conn, :header, expected_names) do
conn.req_headers
|> Enum.filter(fn {key, _value} ->
Enum.member?(expected_names, String.downcase(key))
end)
|> Map.new()
end
defp create_location_schema(parameters) do
properties = Map.new(parameters, fn p -> {p.name, Parameter.schema(p)} end)
%Schema{
type: :object,
additionalProperties: false,
properties: properties,
required: parameters |> Enum.filter(& &1.required) |> Enum.map(& &1.name)
}
|> maybe_add_additional_properties()
end
defp schemas_by_location(operation, components) do
param_specs_by_location =
operation.parameters
|> Enum.map(fn
%Reference{} = ref -> Reference.resolve_parameter(ref, components.parameters)
%Parameter{} = param -> param
end)
|> Enum.group_by(& &1.in)
Map.new(param_specs_by_location, fn {location, parameters} ->
{location, create_location_schema(parameters)}
end)
end
defp cast_location(location, schema, components, conn) do
- params = get_params_by_location(conn, location, Map.keys(schema.properties))
+ params =
+ get_params_by_location(
+ conn,
+ location,
+ schema.properties |> Map.keys() |> Enum.map(&Atom.to_string/1)
+ )
ctx = %Cast{
value: params,
schema: schema,
schemas: components.schemas
}
Object.cast(ctx)
end
defp reduce_cast_results(results) do
Enum.reduce_while(results, {:ok, %{}}, fn
{:ok, params}, {:ok, all_params} -> {:cont, {:ok, Map.merge(all_params, params)}}
cast_error, _ -> {:halt, cast_error}
end)
end
defp maybe_add_additional_properties(schema) do
ap_schema =
Enum.reject(
schema.properties,
fn {_name, %{additionalProperties: ap}} ->
is_nil(ap) or ap == false
end
)
case ap_schema do
[{_, %{additionalProperties: ap}}] -> %{schema | additionalProperties: ap}
_ -> schema
end
end
end
diff --git a/test/support/pet_controller.ex b/test/support/pet_controller.ex
index 17e9231..0707547 100644
--- a/test/support/pet_controller.ex
+++ b/test/support/pet_controller.ex
@@ -1,128 +1,128 @@
defmodule OpenApiSpexTest.PetController do
use Phoenix.Controller
alias OpenApiSpex.Operation
alias OpenApiSpexTest.Schemas
plug OpenApiSpex.Plug.CastAndValidate
def open_api_operation(action) do
apply(__MODULE__, :"#{action}_operation", [])
end
@doc """
API Spec for :show action
"""
def show_operation() do
import Operation
%Operation{
tags: ["pets"],
summary: "Show pet",
description: "Show a pet by ID",
operationId: "PetController.show",
parameters: [
parameter(:id, :path, :integer, "Pet ID", example: 123, minimum: 1)
],
responses: %{
200 => response("Pet", "application/json", Schemas.PetResponse)
}
}
end
def show(conn, %{id: _id}) do
json(conn, %Schemas.PetResponse{
data: %Schemas.Dog{
pet_type: "Dog",
bark: "woof"
}
})
end
def index_operation() do
import Operation
%Operation{
tags: ["pets"],
summary: "List pets",
description: "List all petes",
operationId: "PetController.index",
parameters: [
parameter(:validParam, :query, :boolean, "Valid Param", example: true)
],
responses: %{
200 => response("Pet List Response", "application/json", Schemas.PetsResponse)
}
}
end
def index(conn, _params) do
json(conn, %Schemas.PetsResponse{
data: [
%Schemas.Dog{
pet_type: "Dog",
bark: "joe@gmail.com"
}
]
})
end
def create_operation() do
import Operation
%Operation{
tags: ["pets"],
summary: "Create pet",
description: "Create a pet",
operationId: "PetController.create",
parameters: [],
requestBody: request_body("The pet attributes", "application/json", Schemas.PetRequest),
responses: %{
201 => response("Pet", "application/json", Schemas.PetRequest)
}
}
end
def create(conn = %{body_params: %Schemas.PetRequest{pet: pet}}, _) do
json(conn, %Schemas.PetResponse{
data: pet
})
end
def adopt_operation() do
import Operation
%Operation{
tags: ["pets"],
summary: "Adopt pet",
description: "Adopt a pet",
operationId: "PetController.adopt",
parameters: [
parameter(:"x-user-id", :header, :string, "User that performs this action", required: true),
parameter(:id, :path, :integer, "Pet ID", example: 123, minimum: 1),
parameter(:status, :query, :string, "New status"),
parameter(:debug, :cookie, %OpenApiSpex.Schema{type: :integer, enum: [0, 1], default: 0}, "Debug"),
],
responses: %{
200 => response("Pet", "application/json", Schemas.PetRequest)
}
}
end
- def adopt(conn, %{"x-user-id" => _user_id, :id => _id, :debug => 0}) do
+ def adopt(conn, %{:"x-user-id" => _user_id, :id => _id, :debug => 0}) do
json(conn, %Schemas.PetResponse{
data: %Schemas.Dog{
pet_type: "Dog",
bark: "woof"
}
})
end
- def adopt(conn, %{"x-user-id" => _user_id, :id => _id, :debug => 1}) do
+ def adopt(conn, %{:"x-user-id" => _user_id, :id => _id, :debug => 1}) do
json(conn, %Schemas.PetResponse{
data: %Schemas.Dog{
pet_type: "Debug-Dog",
bark: "woof"
}
})
end
end

File Metadata

Mime Type
text/x-diff
Expires
Tue, Nov 26, 5:43 PM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40448
Default Alt Text
(6 KB)

Event Timeline