open-api-spex / open_api_spex

Open API Specifications for Elixir Plug applications
Mozilla Public License 2.0
706 stars 183 forks source link

Is it possible to pretty print error responses? #585

Closed jozuas closed 9 months ago

jozuas commented 9 months ago

Elixir phoenix allows to customise json_libary and therefore default encode/decode options:

config :phoenix, :json_library, MyApp.JsonWrapper

It does not seems like it's possible to do this for open_api_spex.

Is there some alternative way to achieve pretty printed error responses? Copying and pasting OpenApiSpex.Plug.CastAndValidate with personal changes seems like the only option to me.

zorbash commented 9 months ago

Hi @jozuas!

open_api_spex does not currently allow selecting a json_library.

It'll go for jason if loaded and try to fall back to poison.

# File: open_api.ex
@json_encoder Enum.find([Jason, Poison], &Code.ensure_loaded?/1)
def json_encoder, do: @json_encoder

What you can do is write your own error renderer.

plug OpenApiSpex.Plug.CastAndValidate, render_error: CustomErrorRenderer
defmodule CustomErrorRenderer do
  @behaviour Plug

  alias OpenApiSpex.OpenApi
  alias Plug.Conn

  @impl Plug
  def init(errors), do: errors

  @impl Plug
  def call(conn, errors) when is_list(errors) do
    response = %{
      errors: Enum.map(errors, &render_error/1)
    }

    json = OpenApi.json_encoder().encode!(response, pretty: true) # This will prettify errors

    conn
    |> Conn.put_resp_content_type("application/json")
    |> Conn.send_resp(422, json)
  end

  def call(conn, reason) do
    call(conn, [reason])
  end

  defp render_error(error) do
    pointer = OpenApiSpex.path_to_string(error)

    %{
      title: "Invalid value",
      source: %{
        pointer: pointer
      },
      detail: to_string(error)
    }
  end
end
jozuas commented 9 months ago

Amazing, thank you!

zorbash commented 9 months ago

Closing this, at some point we can either make the json library configurable with:

config :open_api_spex, :json_library, Jason

or

support a json options or the CastAndValidate plug with something like:

plug OpenApiSpex.Plug.CastAndValidate, json_options: [pretty: true]