From ab735d82c21afeea9a2e05292ea8496793711ff9 Mon Sep 17 00:00:00 2001 From: Diederick Lawson Date: Wed, 15 Jan 2025 15:29:24 +0100 Subject: [PATCH] Prefers the built-in JSON library from Elixir 1.18.x when it's available Unfortunately, the JSON module doesn't support the `pretty` option, so that will use either Jason or Poison to encode the API specs in the `openapi.spec.json` mix task. --- lib/mix/tasks/openapi.spec.json.ex | 6 +++++- lib/open_api_spex.ex | 8 ++++---- lib/open_api_spex/open_api.ex | 4 ++-- lib/open_api_spex/plug/render_spec.ex | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/mix/tasks/openapi.spec.json.ex b/lib/mix/tasks/openapi.spec.json.ex index f50cd849..ebb1244c 100644 --- a/lib/mix/tasks/openapi.spec.json.ex +++ b/lib/mix/tasks/openapi.spec.json.ex @@ -42,9 +42,13 @@ defmodule Mix.Tasks.Openapi.Spec.Json do defp maybe_start_app(true), do: Mix.Task.run("app.start") defp maybe_start_app(_), do: Mix.Task.run("app.config", preload_modules: true) + # Unfortunately, the built-in JSON module in Elixir 1.18.x doesn't support the `pretty` option + # So we need to take Jason or Poison to be able to support this feature + defp json_encoder(), do: Enum.find([Jason, Poison], &Code.ensure_loaded?/1) + defp encode(spec, %{pretty: pretty}) do spec - |> OpenApiSpex.OpenApi.json_encoder().encode(pretty: pretty) + |> json_encoder().encode(pretty: pretty) |> case do {:ok, json} -> "#{json}\n" diff --git a/lib/open_api_spex.ex b/lib/open_api_spex.ex index a7d18c74..31e4bafe 100644 --- a/lib/open_api_spex.ex +++ b/lib/open_api_spex.ex @@ -181,7 +181,7 @@ defmodule OpenApiSpex do - ensures the schema is linked to the module by "x-struct" extension property - defines a struct with keys matching the schema properties - defines a @type `t` for the struct - - derives a `Jason.Encoder` and/or `Poison.Encoder` for the struct + - derives a `JSON.Encoder`, `Jason.Encoder` and/or `Poison.Encoder` for the struct See `OpenApiSpex.Schema` for additional examples and details. @@ -238,8 +238,8 @@ defmodule OpenApiSpex do - `:struct?` (boolean) - When false, prevents the automatic generation of a struct definition for the schema module. - `:derive?` (boolean) When false, prevents the automatic generation - of a `@derive` call for either `Poison.Encoder` - or `Jason.Encoder`. Using this option can + of a `@derive` call for either `JSON.Encoder` + `Poison.Encoder` or `Jason.Encoder`. Using this option can prevent "... protocol has already been consolidated ..." compiler warnings. """ @@ -262,7 +262,7 @@ defmodule OpenApiSpex do if Map.get(@schema, :"x-struct") == __MODULE__ do if Keyword.get(unquote(opts), :derive?, true) do - @derive Enum.filter([Poison.Encoder, Jason.Encoder], &Code.ensure_loaded?/1) + @derive Enum.filter([JSON.Encoder, Poison.Encoder, Jason.Encoder], &Code.ensure_loaded?/1) end if Keyword.get(unquote(opts), :struct?, true) do diff --git a/lib/open_api_spex/open_api.ex b/lib/open_api_spex/open_api.ex index 8e8ee1bb..817606bd 100644 --- a/lib/open_api_spex/open_api.ex +++ b/lib/open_api_spex/open_api.ex @@ -70,7 +70,7 @@ defmodule OpenApiSpex.OpenApi do """ @callback spec() :: t - @json_encoder Enum.find([Jason, Poison], &Code.ensure_loaded?/1) + @json_encoder Enum.find([JSON, Jason, Poison], &Code.ensure_loaded?/1) @yaml_encoder nil @vendor_extensions ~w( x-struct @@ -80,7 +80,7 @@ defmodule OpenApiSpex.OpenApi do def json_encoder, do: @json_encoder - for encoder <- [Poison.Encoder, Jason.Encoder] do + for encoder <- [JSON.Encoder, Poison.Encoder, Jason.Encoder] do if Code.ensure_loaded?(encoder) do defimpl encoder do def encode(api_spec = %OpenApi{}, options) do diff --git a/lib/open_api_spex/plug/render_spec.ex b/lib/open_api_spex/plug/render_spec.ex index f07804d3..6a5dd559 100644 --- a/lib/open_api_spex/plug/render_spec.ex +++ b/lib/open_api_spex/plug/render_spec.ex @@ -25,7 +25,7 @@ defmodule OpenApiSpex.Plug.RenderSpec do @behaviour Plug - @json_encoder Enum.find([Jason, Poison], &Code.ensure_loaded?/1) + @json_encoder Enum.find([JSON, Jason, Poison], &Code.ensure_loaded?/1) @impl Plug def init(opts), do: opts