Elixir wrapper for spectra OpenAPI specification generation.
This module provides idiomatic Elixir functions for generating OpenAPI 3.1 specifications from Elixir type definitions using spectra.
Response Builder Pattern
Responses are built using a fluent API:
response = Spectral.OpenAPI.response(200, "Success")
|> Spectral.OpenAPI.response_with_body(Person, :t)
|> Spectral.OpenAPI.response_with_header("X-Rate-Limit", RateLimit, %{
schema: :t,
description: "Remaining requests",
required: false
})
endpoint = Spectral.OpenAPI.endpoint(:get, "/users/{id}")
|> Spectral.OpenAPI.add_response(response)
Summary
Types
An endpoint or a webhook. The builder functions accept both.
Functions
Adds a complete response specification to an endpoint.
Creates a new OpenAPI endpoint definition.
Creates a new OpenAPI endpoint definition using metadata from a spectral/1 macro
placed before a function definition.
Converts a list of endpoints to a complete OpenAPI specification.
Converts a list of endpoints to a complete OpenAPI specification, with options.
Creates a response builder.
Adds a response body to a response builder.
Adds a header to a response builder.
Converts endpoints and webhooks to a complete OpenAPI specification.
Creates a new OpenAPI 3.1 webhook definition.
Marks a webhook whose payload is encoded with nil_fields: :null.
Adds a parameter to an endpoint.
Adds a request body specification to an endpoint.
Types
@type operation() :: :spectra_openapi.endpoint_spec() | :spectra_openapi.webhook_spec()
An endpoint or a webhook. The builder functions accept both.
Functions
@spec add_response(operation(), :spectra_openapi.response_spec()) :: operation()
Adds a complete response specification to an endpoint.
This function adds a response that was built using the response builder pattern.
Parameters
endpoint- The endpoint to add the response toresponse- Response specification built withresponse/2and related functions
Returns
endpoint- Updated endpoint with the response added
Example
response = Spectral.OpenAPI.response(200, "User found")
|> Spectral.OpenAPI.response_with_body(Person, :t)
endpoint = Spectral.OpenAPI.endpoint(:get, "/users/{id}")
|> Spectral.OpenAPI.add_response(response)
@spec endpoint( :spectra_openapi.http_method(), binary(), :spectra_openapi.endpoint_doc() ) :: :spectra_openapi.endpoint_spec()
Creates a new OpenAPI endpoint definition.
Parameters
method- HTTP method as an atom (:get,:post,:put,:delete,:patch, etc.)path- URL path as a binary (e.g.,"/users/{id}")doc- Optional documentation map with optional keys::summary- Short summary of the endpoint:description- Longer description of the endpoint:operationId- Unique string to identify the operation:tags- List of tags for grouping endpoints:deprecated- Whether the endpoint is deprecated (boolean):externalDocs- Map with:url(required) and:description(optional):security- List of Security Requirement Objects for this operation alone, overriding the global:securitydefault.[]opts the operation out of the global requirement entirely.
Returns
endpoint- OpenAPI endpoint structure
Example
iex> endpoint = Spectral.OpenAPI.endpoint(:get, "/users/{id}", %{summary: "Get user by ID"})
iex> endpoint.doc
%{summary: "Get user by ID"}
@spec endpoint( :spectra_openapi.http_method(), binary(), module(), atom(), non_neg_integer() ) :: :spectra_openapi.endpoint_spec()
Creates a new OpenAPI endpoint definition using metadata from a spectral/1 macro
placed before a function definition.
The function's metadata (set via spectral summary: "...", description: "..." before
the corresponding @spec) is retrieved from the module's type info and used as the
endpoint documentation.
Parameters
method- HTTP method as an atom (:get,:post,:put,:delete,:patch, etc.)path- URL path as a binary (e.g.,"/users/{id}")module- The module containing the function withspectralmetadatafunction_name- The function name as an atomarity- The function arity
Returns
endpoint- OpenAPI endpoint structure with documentation from the function's metadata
Example
defmodule MyController do
use Spectral
spectral summary: "Get user", description: "Returns a user by ID"
@spec get_user(map(), map()) :: map()
def get_user(_conn, _params), do: %{}
end
endpoint = Spectral.OpenAPI.endpoint(:get, "/users/{id}", MyController, :get_user, 2)
@spec endpoints_to_openapi(:spectra_openapi.openapi_metadata(), [ :spectra_openapi.endpoint_spec() ]) :: {:ok, iodata()} | {:error, [Spectral.Error.t()]}
Converts a list of endpoints to a complete OpenAPI specification.
Parameters
metadata- OpenAPI metadata map with keys::title- API title (required):version- API version (required):summary(optional) - Short summary of the API:description(optional) - Longer description of the API:terms_of_service(optional) - URL to the terms of service:contact(optional) - Contact map with optional:name,:url,:email:license(optional) - License map with required:nameand optional:url,:identifier:servers(optional) - List of server objects, each with required:urland optional:description
endpoints- List of endpoint definitions
Returns
{:ok, iodata}- Complete OpenAPI 3.1 specification serialised as JSON iodata{:error, [%Spectral.Error{}]}- List of errors if generation fails
Example
metadata = %{title: "My API", version: "1.0.0"}
endpoints = [
Spectral.OpenAPI.endpoint(:get, "/users/{id}")
|> Spectral.OpenAPI.add_response(
Spectral.OpenAPI.response(200, "User found")
|> Spectral.OpenAPI.response_with_body(Person, :t)
)
]
{:ok, json} = Spectral.OpenAPI.endpoints_to_openapi(metadata, endpoints)
@spec endpoints_to_openapi( :spectra_openapi.openapi_metadata(), [:spectra_openapi.endpoint_spec()], [ Spectral.schema_option() ] ) :: {:ok, iodata() | dynamic()} | {:error, [Spectral.Error.t()]}
Converts a list of endpoints to a complete OpenAPI specification, with options.
Like endpoints_to_openapi/2 but accepts an options list.
Parameters
metadata- OpenAPI metadata map (same asendpoints_to_openapi/2)endpoints- List of endpoint definitionsopts- Options list. Supported options::pre_encoded- Return a map instead of iodata, skipping JSON encoding.
Returns
{:ok, iodata()}- Complete OpenAPI 3.1 spec as JSON iodata (default){:ok, map()}- Spec as a decoded map when:pre_encodedoption is set{:error, [%Spectral.Error{}]}- List of errors if generation fails
@spec response(:spectra_openapi.http_status_code(), binary()) :: :spectra_openapi.response_spec()
Creates a response builder.
This creates a response specification that can be further configured with
response_with_body/3-4 and response_with_header/4 before being added
to an endpoint with add_response/2.
Parameters
status_code- HTTP status code (e.g.,200,404,500), or an OpenAPI status code range from"1XX"to"5XX"description- Human-readable description of the response
Returns
response- Response builder structure
Example
response = Spectral.OpenAPI.response(200, "User found successfully")
@spec response_with_body( :spectra_openapi.response_spec(), module(), atom() | :spectra.sp_type_or_ref() ) :: :spectra_openapi.response_spec()
Adds a response body to a response builder.
You can optionally provide a content_type as a 4th argument.
Parameters
response- Response builder fromresponse/2module- Module containing the type definitionschema- Schema reference (typically an atom like:t)content_type- Optional content type (e.g.,"application/json","application/xml")
Returns
response- Updated response builder with body schema
Example
response = Spectral.OpenAPI.response(200, "Success")
|> Spectral.OpenAPI.response_with_body(Person, :t)
response_xml = Spectral.OpenAPI.response(200, "Success")
|> Spectral.OpenAPI.response_with_body(Person, :t, "application/xml")
@spec response_with_header( :spectra_openapi.response_spec(), binary(), module(), map() ) :: :spectra_openapi.response_spec()
Adds a header to a response builder.
Parameters
response- Response builder fromresponse/2header_name- Name of the response header (e.g.,"X-Rate-Limit")module- Module containing the type definition for the header valueheader_spec- Header specification map with keys::schema- Schema reference for the header value (atom like:t, or a type ref tuple):description(optional) - Description of the header:required(optional) - Whether the header is required (default: false):deprecated(optional) - Whether the header is deprecated (boolean)
Returns
response- Updated response builder with header added
Example
response = Spectral.OpenAPI.response(200, "Success")
|> Spectral.OpenAPI.response_with_header("X-Rate-Limit", RateLimit, %{
schema: :t,
description: "Requests remaining",
required: false
})
@spec to_openapi( :spectra_openapi.openapi_metadata(), [:spectra_openapi.endpoint_spec()], [:spectra_openapi.webhook_spec()], [Spectral.schema_option()] ) :: {:ok, iodata() | dynamic()} | {:error, [Spectral.Error.t()]}
Converts endpoints and webhooks to a complete OpenAPI specification.
Like endpoints_to_openapi/3, but also takes webhooks built with
webhook/2,3. They are emitted under the spec's top-level webhooks key,
and their schemas share components/schemas with the endpoints, so a type
used by both is emitted once.
A global :security requirement in the metadata applies to webhooks too.
Override it per operation with :security in the doc map, or [] to opt out.
Parameters
metadata- OpenAPI metadata map (same asendpoints_to_openapi/2)endpoints- List of endpoint definitionswebhooks- List of webhook definitions built withwebhook/2,3opts- Options list. Supported options::pre_encoded- Return a map instead of iodata, skipping JSON encoding.
Returns
{:ok, iodata()}- Complete OpenAPI 3.1 spec as JSON iodata (default){:ok, map()}- Spec as a decoded map when:pre_encodedoption is set{:error, [%Spectral.Error{}]}- List of errors if generation fails
@spec webhook( binary(), :spectra_openapi.http_method(), :spectra_openapi.endpoint_doc() ) :: :spectra_openapi.webhook_spec()
Creates a new OpenAPI 3.1 webhook definition.
A webhook is keyed by an event name and emitted under the spec's top-level
webhooks key by to_openapi/4. Build it with the same functions as an
endpoint. Only :header and :cookie parameters are allowed.
Parameters
name- Event name as a binary (e.g.,"userCreated")method- HTTP method your API uses when calling the consumer (usually:post)doc- Optional documentation map, taking the same keys asendpoint/3
Returns
webhook- OpenAPI webhook structure
Example
iex> webhook = Spectral.OpenAPI.webhook("userCreated", :post, %{summary: "User created"})
iex> webhook.name
"userCreated"
@spec with_nil_fields(:spectra_openapi.webhook_spec(), :null) :: :spectra_openapi.webhook_spec()
Marks a webhook whose payload is encoded with nil_fields: :null.
Use it when the code that sends the webhook calls Spectral.encode/5 with
nil_fields: :null. The payload schema then lists every field whose type can be
nil in required and allows null, nested types included. Headers and
responses do not change.
The payload type keeps its normal schema name. If the same type is also used
without this option, the webhook gets a second schema with Nullable added to
the name. With config :spectra, :nil_fields, :null the option changes nothing.
With :omit, to_openapi/4 raises ArgumentError, and so it does when the
Nullable name is already taken. Any value other than :null raises
ArgumentError.
Example
webhook = Spectral.OpenAPI.webhook("paymentDone", :post)
|> Spectral.OpenAPI.with_request_body(Payment, {:type, :t, 0})
|> Spectral.OpenAPI.with_nil_fields(:null)
@spec with_parameter(operation(), module(), :spectra_openapi.parameter_input_spec()) :: operation()
Adds a parameter to an endpoint.
Parameters can be in the path, query string, headers, or cookies.
Parameters
endpoint- The endpoint or webhook to modifymodule- Module containing the type definition for the parameterparameter_spec- Parameter specification map with keys::name- Parameter name:in- Location (:path,:query,:header,:cookie):required- Whether the parameter is required:schema- Schema for the parameter value (atom or{:type, name, arity}tuple)
The description and deprecated fields in the rendered OpenAPI output are sourced from
the type's spectral annotation, not from the parameter spec. Type aliases and remote type
references are followed automatically to inherit their documentation.
Returns
endpoint- Modified endpoint with parameter added
Example
endpoint = Spectral.OpenAPI.endpoint(:get, "/users/{id}")
|> Spectral.OpenAPI.with_parameter(User, %{
name: "id",
in: :path,
required: true,
schema: :string
})
@spec with_request_body(operation(), module(), atom() | :spectra.sp_type_or_ref()) :: operation()
Adds a request body specification to an endpoint.
You can optionally provide a content_type as a 4th argument.
Parameters
endpoint- The endpoint or webhook to modifymodule- Module containing type definitionsschema- Schema reference (typically an atom like:t)content_type- Optional content type binary (e.g.,"application/xml"; defaults to"application/json")
Returns
endpoint- Modified endpoint with request body
Example
endpoint = Spectral.OpenAPI.endpoint(:post, "/users")
|> Spectral.OpenAPI.with_request_body(Person, :t)
endpoint_xml = Spectral.OpenAPI.endpoint(:post, "/users")
|> Spectral.OpenAPI.with_request_body(Person, :t, "application/xml")