Packages
open_api_spex
3.22.2
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/open_api.ex
defmodule OpenApiSpex.OpenApi do
@moduledoc """
Defines the `OpenApiSpex.OpenApi.t` type and the behaviour for application modules that
construct an `OpenApiSpex.OpenApi.t` at runtime.
"""
alias OpenApiSpex.{
Components,
Example,
Extendable,
ExternalDocumentation,
Info,
MediaType,
OpenApi,
Paths,
Schema,
SecurityRequirement,
Server,
Tag
}
@enforce_keys [:info, :paths]
defstruct openapi: "3.0.0",
info: nil,
servers: [],
paths: nil,
components: nil,
security: [],
tags: [],
externalDocs: nil,
extensions: nil
@typedoc """
[OpenAPI Object](https://swagger.io/specification/#oasObject)
This is the root document object of the OpenAPI document.
"""
@type t :: %OpenApi{
openapi: String.t(),
info: Info.t(),
servers: [Server.t()] | nil,
paths: Paths.t(),
components: Components.t() | nil,
security: [SecurityRequirement.t()] | nil,
tags: [Tag.t()] | nil,
externalDocs: ExternalDocumentation.t() | nil,
extensions: %{String.t() => any()} | nil
}
@doc """
A spec/0 callback function is required for use with the `OpenApiSpex.Plug.PutApiSpec` plug.
## Example
@impl OpenApiSpex.OpenApi
def spec do
%OpenApi{
servers: [
# Populate the Server info from a phoenix endpoint
Server.from_endpoint(MyAppWeb.Endpoint)
],
info: %Info{
title: "My App",
version: "1.0"
},
# populate the paths from a phoenix router
paths: Paths.from_router(MyAppWeb.Router)
}
|> OpenApiSpex.resolve_schema_modules() # discover request/response schemas from path specs
end
"""
@callback spec() :: t
@json_encoder Enum.find([Jason, Poison], &Code.ensure_loaded?/1)
@yaml_encoder nil
@vendor_extensions ~w(
x-struct
x-validate
x-parameter-content-parsers
)
def json_encoder, do: @json_encoder
for encoder <- [Poison.Encoder, Jason.Encoder] do
if Code.ensure_loaded?(encoder) do
defimpl encoder do
def encode(api_spec = %OpenApi{}, options) do
api_spec
|> OpenApi.to_map()
|> unquote(encoder).encode(options)
end
end
end
end
if Code.ensure_loaded?(Ymlr) do
defmodule YmlrEncoder do
@moduledoc false
def encode(api_spec = %OpenApi{}, _options) do
api_spec
|> OpenApi.to_map()
|> Ymlr.document()
end
def encode(api_spec = %{}, _options) do
Ymlr.document(api_spec)
end
end
@yaml_encoder YmlrEncoder
end
def yaml_encoder, do: @yaml_encoder
def to_map(value), do: to_map(value, [])
def to_map(%Regex{source: source}, _opts), do: source
def to_map(%object{} = value, opts) when object in [MediaType, Schema, Example] do
value
|> Extendable.to_map()
|> Stream.map(fn
{:value, v} when object == Example -> {"value", to_map_example(v, opts)}
{:example, v} -> {"example", to_map_example(v, opts)}
{:required, []} when object == Schema -> {"required", nil}
{k, v} -> {to_string(k), to_map(v, opts)}
end)
|> Stream.filter(fn
{:required, []} when object == Schema -> false
{k, _} when k in @vendor_extensions -> opts[:vendor_extensions]
{_, nil} -> false
_ -> true
end)
|> Enum.into(%{})
end
def to_map(value = %{__struct__: _}, opts) do
value
|> Extendable.to_map()
|> to_map(opts)
end
def to_map(value, opts) when is_map(value) do
value
|> Stream.map(fn {k, v} -> {to_string(k), to_map(v, opts)} end)
|> Stream.filter(fn
{_, nil} -> false
_ -> true
end)
|> Enum.into(%{})
end
def to_map(value, opts) when is_list(value) do
Enum.map(value, &to_map(&1, opts))
end
def to_map(nil, _opts), do: nil
def to_map(true, _opts), do: true
def to_map(false, _opts), do: false
def to_map(value, _opts) when is_atom(value), do: to_string(value)
def to_map(value, _opts), do: value
defp to_map_example(value = %{__struct__: _}, opts) do
value
|> Extendable.to_map()
|> to_map_example(opts)
end
defp to_map_example(value, opts) when is_map(value) do
value
|> Stream.map(fn {k, v} -> {to_string(k), to_map_example(v, opts)} end)
|> Enum.into(%{})
end
defp to_map_example(value, opts) when is_list(value) do
Enum.map(value, &to_map_example(&1, opts))
end
defp to_map_example(value, opts), do: to_map(value, opts)
def from_map(map) do
OpenApi.Decode.decode(map)
end
end