Skip to content

Commit 60eda20

Browse files
authored
Merge pull request #102 from open-api-spex/lookup-operation-by-phoenix-controller-action
Add operation lookup by phoenix {controller, action}
2 parents 08e76b4 + 74bf213 commit 60eda20

File tree

3 files changed

+87
-46
lines changed

3 files changed

+87
-46
lines changed

lib/open_api_spex/plug/cache.ex

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
defmodule OpenApiSpex.Plug.Cache do
2+
@moduledoc false
3+
4+
@callback get(module) :: {OpenApiSpex.OpenApi.t(), map} | nil
5+
@callback put(module, {OpenApiSpex.OpenApi.t(), map}) :: :ok
6+
7+
@spec adapter() :: OpenApiSpex.Plug.AppEnvCache | OpenApiSpex.Plug.PersistentTermCache
8+
def adapter do
9+
if function_exported?(:persistent_term, :info, 0) do
10+
OpenApiSpex.Plug.PersistentTermCache
11+
else
12+
OpenApiSpex.Plug.AppEnvCache
13+
end
14+
end
15+
end
16+
17+
defmodule OpenApiSpex.Plug.AppEnvCache do
18+
@moduledoc false
19+
@behaviour OpenApiSpex.Plug.Cache
20+
21+
@impl OpenApiSpex.Plug.Cache
22+
def get(spec_module) do
23+
Application.get_env(:open_api_spex, spec_module)
24+
end
25+
26+
@impl OpenApiSpex.Plug.Cache
27+
def put(spec_module, spec) do
28+
:ok = Application.put_env(:open_api_spex, spec_module, spec)
29+
end
30+
end
31+
32+
if function_exported?(:persistent_term, :info, 0) do
33+
defmodule OpenApiSpex.Plug.PersistentTermCache do
34+
@moduledoc false
35+
@behaviour OpenApiSpex.Plug.Cache
36+
37+
@impl OpenApiSpex.Plug.Cache
38+
def get(spec_module) do
39+
:persistent_term.get(spec_module)
40+
rescue
41+
ArgumentError ->
42+
nil
43+
end
44+
45+
@impl OpenApiSpex.Plug.Cache
46+
def put(spec_module, spec) do
47+
:ok = :persistent_term.put(spec_module, spec)
48+
end
49+
end
50+
end

lib/open_api_spex/plug/cast_and_validate.ex

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,37 @@ defmodule OpenApiSpex.Plug.CastAndValidate do
8080

8181
def call(
8282
conn = %{
83-
private: %{phoenix_controller: controller, phoenix_action: action, open_api_spex: _pd}
83+
private: %{
84+
phoenix_controller: controller,
85+
phoenix_action: action,
86+
open_api_spex: private_data
87+
}
8488
},
8589
opts
8690
) do
87-
operation_id = controller.open_api_operation(action).operationId
91+
operation =
92+
case private_data.operation_lookup[{controller, action}] do
93+
nil ->
94+
operationId = controller.open_api_operation(action).operationId
95+
operation = private_data.operation_lookup[operationId]
8896

89-
if operation_id do
90-
call(conn, Map.put(opts, :operation_id, operation_id))
97+
operation_lookup =
98+
private_data.operation_lookup
99+
|> Map.put({controller, action}, operation)
100+
101+
OpenApiSpex.Plug.Cache.adapter().put(
102+
private_data.spec_module,
103+
{private_data.spec, operation_lookup}
104+
)
105+
106+
operation
107+
108+
operation ->
109+
operation
110+
end
111+
112+
if operation.operationId do
113+
call(conn, Map.put(opts, :operation_id, operation.operationId))
91114
else
92115
raise "operationId was not found in action API spec"
93116
end

lib/open_api_spex/plug/put_api_spec.ex

Lines changed: 10 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ defmodule OpenApiSpex.Plug.PutApiSpec do
99
plug OpenApiSpex.Plug.PutApiSpec, module: MyAppWeb.ApiSpec
1010
"""
1111
@behaviour Plug
12-
@before_compile __MODULE__.Cache
12+
@cache OpenApiSpex.Plug.Cache.adapter()
1313

1414
@impl Plug
1515
def init([module: _spec_module] = opts) do
@@ -19,12 +19,20 @@ defmodule OpenApiSpex.Plug.PutApiSpec do
1919
@impl Plug
2020
def call(conn, spec_module) do
2121
{spec, operation_lookup} =
22-
fetch_spec(spec_module)
22+
case @cache.get(spec_module) do
23+
nil ->
24+
spec = build_spec(spec_module)
25+
@cache.put(spec_module, spec)
26+
spec
27+
spec ->
28+
spec
29+
end
2330

2431
private_data =
2532
conn
2633
|> Map.get(:private)
2734
|> Map.get(:open_api_spex, %{})
35+
|> Map.put(:spec_module, spec_module)
2836
|> Map.put(:spec, spec)
2937
|> Map.put(:operation_lookup, operation_lookup)
3038

@@ -47,44 +55,4 @@ defmodule OpenApiSpex.Plug.PutApiSpec do
4755
|> Stream.map(fn operation -> {operation.operationId, operation} end)
4856
|> Enum.into(%{})
4957
end
50-
51-
defmodule Cache do
52-
defmacro __before_compile__(_env) do
53-
if function_exported?(:persistent_term, :info, 0) do
54-
quote do
55-
def fetch_spec(spec_module) do
56-
try do
57-
:persistent_term.get(spec_module)
58-
rescue
59-
ArgumentError ->
60-
term_not_found()
61-
spec = build_spec(spec_module)
62-
:ok = :persistent_term.put(spec_module, spec)
63-
spec
64-
end
65-
end
66-
67-
defp term_not_found do
68-
if Application.get_env(:open_api_spex, :persistent_term_warn, false) do
69-
IO.warn("Warning: the OpenApiSpec spec was deleted from persistent terms. This can cause serious issues.")
70-
else
71-
Application.put_env(:open_api_spex, :persistent_term, true)
72-
end
73-
end
74-
end
75-
else
76-
quote do
77-
def fetch_spec(spec_module) do
78-
case Application.get_env(:open_api_spex, spec_module) do
79-
nil ->
80-
spec = build_spec(spec_module)
81-
Application.put_env(:open_api_spex, spec_module, spec)
82-
spec
83-
spec -> spec
84-
end
85-
end
86-
end
87-
end
88-
end
89-
end
9058
end

0 commit comments

Comments
 (0)