Packages
open_api_spex
3.16.0
3.22.3
3.22.2
3.22.1
3.22.0
3.21.5
3.21.4
3.21.3
3.21.2
3.21.1
3.21.0
3.20.1
3.20.0
3.19.1
3.19.0
3.18.3
3.18.2
3.18.1
3.18.0
3.17.3
3.17.2
3.17.1
3.17.0
3.16.4
3.16.3
3.16.2
3.16.1
3.16.0
3.15.0
3.14.0
3.13.0
3.12.0
3.11.0
3.10.0
3.9.0
3.8.0
3.7.0
3.6.0
3.5.2
3.5.1
3.5.0
3.4.0
3.3.0
3.2.1
3.2.0
3.1.0
3.0.0
2.3.1
2.3.0
2.2.0
2.1.1
2.1.0
2.0.0
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.1
1.0.0
Leverage Open Api Specification 3 (swagger) to document, test, validate and explore your Plug and Phoenix APIs.
Current section
Files
Jump to
Current section
Files
lib/open_api_spex/plug/put_api_spec.ex
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.
## Options
- module: A module implementing the `OpenApiSpex.OpenApi` behaviour
## Example
plug OpenApiSpex.Plug.PutApiSpec, module: MyAppWeb.ApiSpec
"""
alias OpenApiSpex.{OpenApi, Operation, Plug.Cache}
alias Plug.Conn
@behaviour Plug
@missing_oas_key "Missing private.open_api_spex key in conn. Check that PutApiSpec is being called in the Conn pipeline"
@impl Plug
def init(opts) do
opts[:module] ||
raise "A :module option is required, but none was given to #{__MODULE__}.init/1"
end
@impl Plug
def call(conn, spec_module) do
private_data =
conn
|> Map.get(:private)
|> Map.get(:open_api_spex, %{})
|> Map.put(:spec_module, spec_module)
Plug.Conn.put_private(conn, :open_api_spex, private_data)
end
@spec get_spec_and_operation_lookup(Conn.t()) ::
{spec :: OpenApi.t(), operation_lookup :: %{any => Operation.t()}}
def get_spec_and_operation_lookup(conn) do
spec_module = spec_module(conn)
spec_and_lookup = cache().get(spec_module)
if spec_and_lookup do
spec_and_lookup
else
spec = spec_module.spec()
operation_lookup = build_operation_lookup(spec)
spec_and_lookup = {spec, operation_lookup}
cache().put(spec_module, spec_and_lookup)
spec_and_lookup
end
end
@spec get_and_cache_controller_action(Conn.t(), String.t(), {module, atom}) ::
Operation.t()
def get_and_cache_controller_action(conn, operation_id, {controller, action}) do
spec_module = spec_module(conn)
{spec, operation_lookup} = get_spec_and_operation_lookup(conn)
operation = operation_lookup[operation_id]
operation_lookup = Map.put(operation_lookup, {controller, action}, operation)
cache().put(spec_module, {spec, operation_lookup})
operation
end
@spec spec_module(Conn.t()) :: module
def spec_module(conn) do
private_data = Map.get(conn.private, :open_api_spex) || raise @missing_oas_key
private_data.spec_module
end
@spec build_operation_lookup(OpenApi.t()) :: %{
String.t() => OpenApiSpex.Operation.t()
}
defp build_operation_lookup(%OpenApi{} = spec) 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
@spec cache() :: module
defp cache do
Cache.adapter()
end
end