Page MenuHomePhorge

No OneTemporary

Size
6 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/open_api_spex/plug/cast.ex b/lib/open_api_spex/plug/cast.ex
index 0a7f8a5..5babe18 100644
--- a/lib/open_api_spex/plug/cast.ex
+++ b/lib/open_api_spex/plug/cast.ex
@@ -1,58 +1,85 @@
defmodule OpenApiSpex.Plug.Cast do
@moduledoc """
Module plug that will cast the `Conn.params` according to the schemas defined for the operation.
The operation_id can be given at compile time as an argument to `init`:
plug OpenApiSpex.Plug.Cast, operation_id: "MyApp.ShowUser"
For phoenix applications, the operation_id can be obtained at runtime automatically.
defmodule MyAppWeb.UserController do
use Phoenix.Controller
plug OpenApiSpex.Plug.Cast
...
end
+
+ If you want customize the error response, you can provide the `:render_error` options, which points to a function
+ with two arguments of the types Plug.Conn and string, where string contains the reason of the error. The function is
+ called when a validation error occurs.
+
+ ## Example
+
+ defmodule MyAppWeb.UserController do
+ use Phoenix.Controller
+ plug OpenApiSpex.Plug.Cast,
+ render_error: &MyAppWeb.UserController.render_error/2
+
+ plug OpenApiSpex.Plug.Validate
+
+ def render_error(conn, reason) do
+ msg = %{error: reason} |> Posion.encode!()
+
+ conn
+ |> Conn.put_resp_content_type("application/json")
+ |> Conn.send_resp(400, msg)
+ end
+ ...
+ end
"""
@behaviour Plug
alias Plug.Conn
@impl Plug
- def init(opts), do: opts
+ def init(opts), do: Keyword.put_new(opts, :render_error, &OpenApiSpex.Plug.Cast.render_error/2)
@impl Plug
- def call(conn = %{private: %{open_api_spex: private_data}}, operation_id: operation_id) do
+ def call(conn = %{private: %{open_api_spex: private_data}}, operation_id: operation_id, render_error: render_error) do
spec = private_data.spec
operation = private_data.operation_lookup[operation_id]
content_type = Conn.get_req_header(conn, "content-type")
|> Enum.at(0)
|> String.split(";")
|> Enum.at(0)
private_data = Map.put(private_data, :operation_id, operation_id)
conn = Conn.put_private(conn, :open_api_spex, private_data)
case OpenApiSpex.cast(spec, operation, conn, content_type) do
{:ok, params} -> %{conn | params: params}
{:error, reason} ->
conn
- |> Plug.Conn.send_resp(422, "#{reason}")
+ |> render_error.(reason)
|> Plug.Conn.halt()
end
end
- def call(conn = %{private: %{phoenix_controller: controller, phoenix_action: action, open_api_spex: _pd}}, _opts) do
+ def call(conn = %{private: %{phoenix_controller: controller, phoenix_action: action, open_api_spex: _pd}}, opts) do
operation_id = controller.open_api_operation(action).operationId
if (operation_id) do
- call(conn, operation_id: operation_id)
+ call(conn, Keyword.put(opts, :operation_id, operation_id))
else
raise "operationId was not found in action API spec"
end
end
def call(_conn = %{private: %{open_api_spex: _pd}}, _opts) do
raise ":operation_id was neither provided nor inferred from conn. Consider putting plug OpenApiSpex.Plug.Cast rather into your phoenix controller."
end
def call(_conn, _opts) do
raise ":open_api_spex was not found under :private. Maybe OpenApiSpex.Plug.PutApiSpec was not called before?"
end
+
+ def render_error(conn, reason) do
+ conn |> Conn.send_resp(422, "#{reason}")
+ end
end
diff --git a/lib/open_api_spex/plug/validate.ex b/lib/open_api_spex/plug/validate.ex
index 72455b7..dcd515d 100644
--- a/lib/open_api_spex/plug/validate.ex
+++ b/lib/open_api_spex/plug/validate.ex
@@ -1,45 +1,71 @@
defmodule OpenApiSpex.Plug.Validate do
@moduledoc """
Module plug that validates params against the schema defined for an operation.
If validation fails, the plug will send a 422 response with the reason as the body.
This plug should always be run after `OpenApiSpex.Plug.Cast`, as it expects the params map to
have atom keys and query params converted from strings to the appropriate types.
## Example
defmodule MyApp.UserController do
use Phoenix.Controller
plug OpenApiSpex.Plug.Cast
plug OpenApiSpex.Plug.Validate
...
end
+
+ If you want customize the error response, you can provide the `:render_error` options which points to a function
+ with two arguments of the types Plug.Conn and string, where string contains the reason of the error. The function is
+ called when a validation error occurs.
+
+ ## Example
+
+ defmodule MyApp.UserController do
+ use Phoenix.Controller
+ plug OpenApiSpex.Plug.Cast
+ plug OpenApiSpex.Plug.Validate,
+ render_error: &MyApp.UserController.render_error/2
+
+ def render_error(conn, reason) do
+ msg = %{error: reason} |> Posion.encode!()
+
+ conn
+ |> Conn.put_resp_content_type("application/json")
+ |> Conn.send_resp(400, msg)
+ end
+ ...
+ end
"""
@behaviour Plug
alias Plug.Conn
@impl Plug
- def init(opts), do: opts
+ def init(opts), do: Keyword.put_new(opts, :render_error, &OpenApiSpex.Plug.Validate.render_error/2)
@impl Plug
- def call(conn, _opts) do
+ def call(conn, render_error: render_error) do
spec = conn.private.open_api_spex.spec
operation_id = conn.private.open_api_spex.operation_id
operation_lookup = conn.private.open_api_spex.operation_lookup
operation = operation_lookup[operation_id]
content_type = Conn.get_req_header(conn, "content-type")
|> Enum.at(0)
|> String.split(";")
|> Enum.at(0)
with :ok <- OpenApiSpex.validate(spec, operation, conn, content_type) do
conn
else
{:error, reason} ->
conn
- |> Conn.send_resp(422, "#{reason}")
+ |> render_error.(reason)
|> Conn.halt()
end
end
+
+ def render_error(conn, reason) do
+ conn |> Conn.send_resp(422, "#{reason}")
+ end
end
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Sun, Dec 1, 10:53 PM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41869
Default Alt Text
(6 KB)

Event Timeline