1 # Pleroma: A lightweight social networking server
2 # Copyright © 2019-2020 Moxley Stratton, Mike Buhot <https://github.com/open-api-spex/open_api_spex>, MPL-2.0
3 # Copyright © 2020 Pleroma Authors <https://pleroma.social/>
4 # SPDX-License-Identifier: AGPL-3.0-only
6 defmodule Pleroma.Web.ApiSpec.CastAndValidate do
8 This plug is based on [`OpenApiSpex.Plug.CastAndValidate`]
9 (https://github.com/open-api-spex/open_api_spex/blob/master/lib/open_api_spex/plug/cast_and_validate.ex).
10 The main difference is ignoring unexpected query params
11 instead of throwing an error. Also, the default rendering
12 error module is `Pleroma.Web.ApiSpec.RenderError`.
23 |> Map.put_new(:render_error, Pleroma.Web.ApiSpec.RenderError)
27 def call(%{private: %{open_api_spex: private_data}} = conn, %{
28 operation_id: operation_id,
29 render_error: render_error
31 spec = private_data.spec
32 operation = private_data.operation_lookup[operation_id]
35 case Conn.get_req_header(conn, "content-type") do
45 private_data = Map.put(private_data, :operation_id, operation_id)
46 conn = Conn.put_private(conn, :open_api_spex, private_data)
48 case cast_and_validate(spec, operation, conn, content_type) do
53 opts = render_error.init(reason)
56 |> render_error.call(opts)
64 phoenix_controller: controller,
65 phoenix_action: action,
66 open_api_spex: private_data
72 case private_data.operation_lookup[{controller, action}] do
74 operation_id = controller.open_api_operation(action).operationId
75 operation = private_data.operation_lookup[operation_id]
78 private_data.operation_lookup
79 |> Map.put({controller, action}, operation)
81 OpenApiSpex.Plug.Cache.adapter().put(
82 private_data.spec_module,
83 {private_data.spec, operation_lookup}
92 if operation.operationId do
93 call(conn, Map.put(opts, :operation_id, operation.operationId))
95 raise "operationId was not found in action API spec"
99 def call(conn, opts), do: OpenApiSpex.Plug.CastAndValidate.call(conn, opts)
101 defp cast_and_validate(spec, operation, conn, content_type) do
102 case OpenApiSpex.cast_and_validate(spec, operation, conn, content_type) do
106 # Remove unexpected query params and cast/validate again
109 Enum.reduce(errors, conn.query_params, fn
110 %{reason: :unexpected_field, name: name, path: [name]}, params ->
111 Map.delete(params, name)
113 %{reason: :invalid_enum, name: nil, path: path, value: value}, params ->
114 path = path |> Enum.reverse() |> tl() |> Enum.reverse() |> list_items_to_string()
115 update_in(params, path, &List.delete(&1, value))
121 conn = %Conn{conn | query_params: query_params}
122 OpenApiSpex.cast_and_validate(spec, operation, conn, content_type)
126 defp list_items_to_string(list) do
128 i when is_atom(i) -> to_string(i)