Page MenuHomePhorge

No OneTemporary

Size
3 KB
Referenced Files
None
Subscribers
None
diff --git a/.travis.yml b/.travis.yml
index e854ce1..76acdd8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,19 +1,21 @@
language: elixir
elixir:
- 1.6
- 1.7
+ - 1.8
otp_release:
- 20.3
- 21.0
+ - 21.2
script:
- mix compile --warnings-as-errors
- mix test
- mix dialyzer --halt-exit-status
cache:
directories:
- _build
- deps
diff --git a/lib/open_api_spex/plug/put_api_spec.ex b/lib/open_api_spex/plug/put_api_spec.ex
index 9b02f83..3188cf1 100644
--- a/lib/open_api_spex/plug/put_api_spec.ex
+++ b/lib/open_api_spex/plug/put_api_spec.ex
@@ -1,51 +1,90 @@
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
+ @before_compile __MODULE__.Cache
@impl Plug
- def init(opts = [module: _mod]), do: opts
+ def init([module: _spec_module] = opts) do
+ opts[:module]
+ end
@impl Plug
- def call(conn, module: mod) do
+ def call(conn, spec_module) do
{spec, operation_lookup} =
- case Application.get_env(:open_api_spex, mod) do
- nil -> build_spec(mod)
- cached -> cached
- end
+ fetch_spec(spec_module)
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
+
+ defmodule Cache do
+ defmacro __before_compile__(_env) do
+ if function_exported?(:persistent_term, :info, 0) do
+ quote do
+ def fetch_spec(spec_module) 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 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
+ else
+ quote do
+ def fetch_spec(spec_module) 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
+ end
+ end
+ end
+ end
+end

File Metadata

Mime Type
text/x-diff
Expires
Sat, Nov 30, 9:31 AM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41410
Default Alt Text
(3 KB)

Event Timeline