Page MenuHomePhorge

No OneTemporary

Size
2 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/open_api_spex/plug/put_api_spec.ex b/lib/open_api_spex/plug/put_api_spec.ex
index 9b02f83..d5d7b34 100644
--- a/lib/open_api_spex/plug/put_api_spec.ex
+++ b/lib/open_api_spex/plug/put_api_spec.ex
@@ -1,51 +1,83 @@
defmodule OpenApiSpex.Plug.PutApiSpec do
@moduledoc """
Module plug that calls a given module to obtain the Api Spec and store it as private in the Conn.
This allows downstream plugs to use the API spec for casting, validating and rendering.
## Example
plug OpenApiSpex.Plug.PutApiSpec, module: MyAppWeb.ApiSpec
"""
@behaviour Plug
@impl Plug
- def init(opts = [module: _mod]), do: opts
+ def init([module: _spec_module] = opts) do
+ if function_exported?(:persistent_term, :info, 0) do
+ {opts[:module], :term}
+ else
+ {opts[:module], :env}
+ end
+ end
@impl Plug
- def call(conn, module: mod) do
+ def call(conn, {spec_module, storage}) do
{spec, operation_lookup} =
- case Application.get_env(:open_api_spex, mod) do
- nil -> build_spec(mod)
- cached -> cached
- end
+ fetch_spec(spec_module, storage)
private_data =
conn
|> Map.get(:private)
|> Map.get(:open_api_spex, %{})
|> Map.put(:spec, spec)
|> Map.put(:operation_lookup, operation_lookup)
Plug.Conn.put_private(conn, :open_api_spex, private_data)
end
@spec build_spec(module) :: {OpenApiSpex.OpenApi.t, %{String.t => OpenApiSpex.Operation.t}}
defp build_spec(mod) do
spec = mod.spec()
operation_lookup = build_operation_lookup(spec)
- Application.put_env(:open_api_spex, mod, {spec, operation_lookup})
{spec, operation_lookup}
end
@spec build_operation_lookup(OpenApiSpex.OpenApi.t) :: %{String.t => OpenApiSpex.Operation.t}
defp build_operation_lookup(spec = %OpenApiSpex.OpenApi{}) do
spec
|> Map.get(:paths)
|> Stream.flat_map(fn {_name, item} -> Map.values(item) end)
|> Stream.filter(fn x -> match?(%OpenApiSpex.Operation{}, x) end)
|> Stream.map(fn operation -> {operation.operationId, operation} end)
|> Enum.into(%{})
end
-end
\ No newline at end of file
+
+ defp fetch_spec(spec_module, :term) do
+ try do
+ :persistent_term.get(spec_module)
+ rescue
+ ArgumentError ->
+ term_not_found()
+ spec = build_spec(spec_module)
+ :ok = :persistent_term.put(spec_module, spec)
+ spec
+ end
+ end
+
+ defp fetch_spec(spec_module, :env) do
+ case Application.get_env(:open_api_spex, spec_module) do
+ nil ->
+ spec = build_spec(spec_module)
+ Application.put_env(:open_api_spex, spec_module, spec)
+ spec
+ spec -> spec
+ end
+ end
+
+ defp term_not_found do
+ if Application.get_env(:open_api_spex, :persistent_term_warn, false) do
+ IO.warn("Warning: the OpenApiSpec spec was deleted from persistent terms. This can cause serious issues.")
+ else
+ Application.put_env(:open_api_spex, :persistent_term, true)
+ end
+ end
+end

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 30, 11:50 AM (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41424
Default Alt Text
(2 KB)

Event Timeline