Spectral (Spectral v0.13.0)
View SourceElixir wrapper for the Erlang spectra library.
Provides idiomatic Elixir interfaces for encoding, decoding, and schema generation based on type specifications.
API
All functions are designed to work well with Elixir's pipe and with operators:
%Person{name: "Alice", age: 30}
|> Spectral.encode!(Person, :t)
|> send_response()
with {:ok, json} <- Spectral.encode(%Person{name: "Alice"}, Person, :t) do
send_response(json)
end
Summary
Types
Options for schema/4.
A spectra type structure or type reference. sp_type() is an opaque Erlang record.
A reference to a named type {:type, name, arity} or record {:record, name}.
Spectra type information for a module. Alias for :spectra.type_info().
Functions
Sets up the Spectral macros and injects __spectra_type_info__/0.
Decodes data from the specified format.
Decodes data from the specified format, raising on error.
Encodes data to the specified format.
Encodes data to the specified format, raising on error.
Generates a schema for the specified type.
Generates a schema for the specified type, with options.
Adds documentation metadata for a type.
Types
@type decode_option() :: :pre_decoded | {:pre_decoded, boolean()}
Options for decode/5 and decode!/5.
:pre_decoded- Accept an already-decoded JSON term as input, skipping the JSON parsing step. Equivalent to{:pre_decoded, true}.{:pre_decoded, boolean()}- Explicit boolean form;falsegives the default behaviour.
@type encode_option() :: :pre_encoded | {:pre_encoded, boolean()}
Options for encode/5 and encode!/5.
:pre_encoded- Skip the final JSON serialization step and return the intermediate JSON term (a map/list) instead of iodata. Equivalent to{:pre_encoded, true}.{:pre_encoded, boolean()}- Explicit boolean form;falsegives the default behaviour.
@type schema_option() :: :pre_encoded | {:pre_encoded, boolean()}
Options for schema/4.
:pre_encoded- Skip the final JSON serialization step and return a map instead of iodata. Equivalent to{:pre_encoded, true}.{:pre_encoded, boolean()}- Explicit boolean form;falsegives the default behaviour.
@type sp_type_or_ref() :: :spectra.sp_type_or_ref()
A spectra type structure or type reference. sp_type() is an opaque Erlang record.
@type sp_type_reference() :: {:type, atom(), non_neg_integer()} | {:record, atom()}
A reference to a named type {:type, name, arity} or record {:record, name}.
@type type_info() :: :spectra.type_info()
Spectra type information for a module. Alias for :spectra.type_info().
Functions
Sets up the Spectral macros and injects __spectra_type_info__/0.
When you use Spectral, the spectral/1 macro is imported and a
__spectra_type_info__/0 function is injected that Spectral's encode, decode,
and schema functions use internally.
Annotating Types
Place spectral/1 immediately before a @type to attach documentation
to generated JSON schemas and OpenAPI component schemas:
defmodule Person do
use Spectral
defstruct [:name, :age]
spectral title: "Person", description: "A person record"
@type t :: %Person{name: String.t(), age: non_neg_integer()}
endTypes without a spectral call will not have title/description in their schemas.
See spectral/1 for the full list of supported annotation fields.
Annotating Functions (Endpoint Documentation)
Place spectral/1 immediately before a @spec to attach endpoint metadata,
which Spectral.OpenAPI.endpoint/5 reads automatically:
defmodule MyController do
use Spectral
spectral summary: "Get user", description: "Returns a user by ID"
@spec show(map(), map()) :: map()
def show(_conn, _params), do: %{}
end
endpoint = Spectral.OpenAPI.endpoint(:get, "/users/{id}", MyController, :show, 2)
@spec decode(dynamic(), module() | type_info(), atom() | sp_type_or_ref(), atom(), [ decode_option() ]) :: {:ok, dynamic()} | {:error, [Spectral.Error.t()]}
Decodes data from the specified format.
Parameters
data- The data to decode (binary for JSON, string for string format; or a JSON term when:pre_decodedoption is set)module- Module containing the type definitiontype_ref- Type reference (typically an atom like:t)format- Format to decode from (default::json)opts- Options list (default:[]). Supported options::pre_decoded- Accept an already-decoded JSON term as input, skipping JSON parsing.
Returns
{:ok, dynamic()}- Decoded data on success{:error, [%Spectral.Error{}]}- List of errors on failure
Examples
iex> ~s({"name":"Alice","age":30,"address":{"street":"Ystader Straße", "city": "Berlin"}})
...> |> Spectral.decode(Person, :t)
{:ok, %Person{age: 30, name: "Alice", address: %Person.Address{street: "Ystader Straße", city: "Berlin"}}}
iex> ~s({"name":"Alice"})
...> |> Spectral.decode(Person, :t)
{:ok, %Person{age: nil, name: "Alice", address: nil}}
iex> ~s({"name":"Alice","age":30,"extra_field":"ignored"})
...> |> Spectral.decode(Person, :t)
{:ok, %Person{age: 30, name: "Alice", address: nil}}
iex> Spectral.decode(%{"name" => "Alice", "age" => 30}, Person, :t, :json, [:pre_decoded])
{:ok, %Person{age: 30, name: "Alice", address: nil}}
@spec decode!(dynamic(), module() | type_info(), atom() | sp_type_or_ref(), atom(), [ decode_option() ]) :: dynamic()
Decodes data from the specified format, raising on error.
Like decode/5 but raises Spectral.Error instead of returning an error tuple.
Parameters
data- The data to decode (binary for JSON, string for string format; or a JSON term when:pre_decodedoption is set)module- Module containing the type definitiontype_ref- Type reference (typically an atom like:t)format- Format to decode from (default::json)opts- Options list (default:[]). Supported options::pre_decoded- Accept an already-decoded JSON term as input, skipping JSON parsing.
Returns
dynamic()- Decoded data on success
Raises
Spectral.Error- If decoding fails
Examples
iex> ~s({"name":"Alice","age":30})
...> |> Spectral.decode!(Person, :t)
%Person{age: 30, name: "Alice", address: nil}
@spec encode(dynamic(), module() | type_info(), atom() | sp_type_or_ref(), atom(), [ encode_option() ]) :: {:ok, iodata() | dynamic()} | {:error, [Spectral.Error.t()]}
Encodes data to the specified format.
Parameters
data- The data to encodemodule- Module containing the type definitiontype_ref- Type reference (typically an atom like:t)format- Format to encode to (default::json)opts- Options list (default:[]). Supported options::pre_encoded- Return the intermediate JSON term (map/list) instead of iodata.
Returns
{:ok, iodata()}- Encoded data on success (default){:ok, dynamic()}- Encoded data as a JSON term when:pre_encodedoption is set{:error, [%Spectral.Error{}]}- List of errors on failure
Examples
iex> person = %Person{name: "Alice", age: 30, address: %Person.Address{street: "Ystader Straße", city: "Berlin"}}
...> with {:ok, json} <- Spectral.encode(person, Person, :t) do
...> IO.iodata_to_binary(json)
...> end
~s({"address":{"city":"Berlin","street":"Ystader Straße"},"age":30,"name":"Alice"})
iex> {:ok, json} = %Person{name: "Alice"} |> Spectral.encode(Person, :t)
iex> IO.iodata_to_binary(json)
~s({"name":"Alice"})
iex> {:ok, term} = %Person{name: "Alice", age: 30} |> Spectral.encode(Person, :t, :json, [:pre_encoded])
iex> term["name"]
"Alice"
@spec encode!(dynamic(), module() | type_info(), atom() | sp_type_or_ref(), atom(), [ encode_option() ]) :: iodata() | dynamic()
Encodes data to the specified format, raising on error.
Like encode/5 but raises Spectral.Error instead of returning an error tuple.
Parameters
data- The data to encodemodule- Module containing the type definitiontype_ref- Type reference (typically an atom like:t)format- Format to encode to (default::json)opts- Options list (default:[]). Supported options::pre_encoded- Return the intermediate JSON term (map/list) instead of iodata.
Returns
iodata()- Encoded data on success (default)dynamic()- Encoded data as a JSON term when:pre_encodedoption is set
Raises
Spectral.Error- If encoding fails
Examples
iex> %Person{name: "Alice", age: 30}
...> |> Spectral.encode!(Person, :t)
...> |> IO.iodata_to_binary()
~s({"age":30,"name":"Alice"})
Generates a schema for the specified type.
Parameters
module- Module containing the type definitiontype_ref- Type reference (typically an atom like:t)format- Schema format (default::json_schema)
Returns
iodata()- Generated schema
Examples
iex> schemadata = Spectral.schema(Person, :t)
iex> is_binary(IO.iodata_to_binary(schemadata))
true
@spec schema(module() | type_info(), atom() | sp_type_or_ref(), atom(), [ schema_option() ]) :: iodata() | dynamic()
Generates a schema for the specified type, with options.
Like schema/3 but accepts an options list.
Parameters
module- Module containing the type definitiontype_ref- Type reference (typically an atom like:t)format- Schema format (default::json_schema)opts- Options list. Supported options::pre_encoded- Return a map instead of iodata, skipping JSON encoding.
Returns
iodata()- Generated schema (default)dynamic()- Schema as a map when:pre_encodedoption is set
Examples
iex> schema = Spectral.schema(Person, :t, :json_schema, [:pre_encoded])
iex> is_map(schema)
true
Adds documentation metadata for a type.
Use this macro immediately before a @type definition to document it.
The line number is automatically captured to pair the documentation
with the correct type.
Example
defmodule Person do
use Spectral
spectral title: "Person", description: "A person record"
@type t :: %Person{name: String.t()}
endFields — before a @type
title- A short title for the typedescription- A detailed descriptiondeprecated- Whether the type is deprecated (boolean)examples- Example values (list)examples_function-{module, function_name, args}tuple; called at schema generation time to produce examples. The function must be exported.type_parameters- Static configuration forwarded as theparamsargument toSpectral.Codeccallbacks for this type (any term)only- List of field name atoms to include when encoding, decoding, and generating schemas. Fields not in the list are silently dropped. For Elixir structs, excluded fields are filled from the struct's defaults on decode.field_aliases- Map of field name atoms (or integers for integer map keys) to JSON key binaries, e.g.%{first_name: "firstName"}. Applies to struct fields and map literal keys. Applied afteronlyfiltering.
Fields — before a @spec
summary- Short one-line summary of the function / endpointdescription- A detailed descriptiondeprecated- Whether the function is deprecated (boolean)