Packages
open_api_spex
3.16.4
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/swagger_ui.ex
defmodule OpenApiSpex.Plug.SwaggerUI do
@moduledoc """
Module plug that serves SwaggerUI.
The full path to the API spec must be given as a plug option.
The API spec should be served at the given path, see `OpenApiSpex.Plug.RenderSpec`
## Configuring SwaggerUI
SwaggerUI can be configured through plug `opts`.
All options will be converted from `snake_case` to `camelCase` and forwarded to the `SwaggerUIBundle` constructor.
See the [swagger-ui configuration docs](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/) for details.
Should dynamic configuration be required, the `config_url` option can be set to an API endpoint that will provide additional config.
## Example
scope "/" do
pipe_through :browser # Use the default browser stack
get "/", MyAppWeb.PageController, :index
get "/swaggerui", OpenApiSpex.Plug.SwaggerUI,
path: "/api/openapi",
default_model_expand_depth: 3,
display_operation_id: true
end
# Other scopes may use custom stacks.
scope "/api" do
pipe_through :api
resources "/users", MyAppWeb.UserController, only: [:index, :create, :show]
get "/openapi", OpenApiSpex.Plug.RenderSpec, :show
end
"""
@behaviour Plug
@html """
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.14.0/swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body {
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.14.0/swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/4.14.0/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function() {
// Begin Swagger UI call region
const api_spec_url = new URL(window.location);
api_spec_url.pathname = "<%= config.path %>";
api_spec_url.hash = "";
const ui = SwaggerUIBundle({
url: api_spec_url.href,
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
requestInterceptor: function(request){
server_base = window.location.protocol + "//" + window.location.host;
if(request.url.startsWith(server_base)) {
request.headers["x-csrf-token"] = "<%= csrf_token %>";
} else {
delete request.headers["x-csrf-token"];
}
return request;
}
<%= for {k, v} <- Map.drop(config, [:path, :oauth]) do %>
, <%= camelize(k) %>: <%= encode_config(camelize(k), v) %>
<% end %>
})
// End Swagger UI call region
<%= if config[:oauth] do %>
ui.initOAuth(
<%= config.oauth
|> Map.new(fn {k, v} -> {camelize(k), v} end)
|> OpenApiSpex.OpenApi.json_encoder().encode!()
%>
)
<% end %>
window.ui = ui
}
</script>
</body>
</html>
"""
@ui_config_methods [
"operationsSorter",
"tagsSorter",
"onComplete",
"requestInterceptor",
"responseInterceptor",
"modelPropertyMacro",
"parameterMacro",
"initOAuth",
"preauthorizeBasic",
"preauthorizeApiKey"
]
@doc """
Initializes the plug.
## Options
* `:path` - Required. The URL path to the API definition.
* `:oauth` - Optional. Config to pass to the `SwaggerUIBundle.initOAuth()` function.
* all other opts - forwarded to the `SwaggerUIBundle` constructor
## Example
get "/swaggerui", OpenApiSpex.Plug.SwaggerUI,
path: "/api/openapi",
default_model_expand_depth: 3,
display_operation_id: true
"""
@impl Plug
def init(opts) when is_list(opts) do
Map.new(opts)
end
@impl Plug
def call(conn, config) do
csrf_token = Plug.CSRFProtection.get_csrf_token()
config = supplement_config(config, conn)
html = render(config, csrf_token)
conn
|> Plug.Conn.put_resp_content_type("text/html")
|> Plug.Conn.send_resp(200, html)
end
require EEx
EEx.function_from_string(:defp, :render, @html, [
:config,
:csrf_token
])
defp camelize(identifier) do
identifier
|> to_string
|> String.split("_", parts: 2)
|> case do
[first] -> first
[first, rest] -> first <> Macro.camelize(rest)
end
end
defp encode_config("tagsSorter", "alpha" = value) do
OpenApiSpex.OpenApi.json_encoder().encode!(value)
end
defp encode_config("operationsSorter", value) when value == "alpha" or value == "method" do
OpenApiSpex.OpenApi.json_encoder().encode!(value)
end
defp encode_config(key, value) do
case Enum.member?(@ui_config_methods, key) do
true -> value
false -> OpenApiSpex.OpenApi.json_encoder().encode!(value)
end
end
if Code.ensure_loaded?(Phoenix.Controller) do
defp supplement_config(%{oauth2_redirect_url: {:endpoint_url, path}} = config, conn) do
endpoint_module = Phoenix.Controller.endpoint_module(conn)
url = Path.join(endpoint_module.url(), path)
Map.put(config, :oauth2_redirect_url, url)
end
end
defp supplement_config(config, _conn) do
config
end
end