Changelog
View SourceAll notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
[0.12.1] - 2026-04-24
Fixed
#{}(empty-map type) in JSON encode/decode now accepts any map input again — additional fields are silently dropped, matching the behaviour of other literal-field maps. The overly strict rejection introduced in 0.12.0 caused valid use-cases (unconstrained map types) to fail unexpectedly.
[0.12.0] - 2026-04-24
Added
- Custom codec can now operate on remote types from modules compiled without
debug_info. Previously this required debug info to be present; now spectra falls back gracefully and the codec handles decoding directly.
Changed
- Breaking: Custom codec callback signatures have changed. All three callbacks (
encode,decode,schema) now receiveCallerTypeInfo :: spectra:type_info()instead of a bareModule :: atom(), and a newTargetTypeRef :: spectra:sp_type_reference()argument is added beforeTargetType. The arities are:encode/6,decode/6,schema/5. The argument order is(Format, CallerTypeInfo, TargetTypeRef, TargetType, Data, Config)forencode/decodeand(Format, CallerTypeInfo, TargetTypeRef, TargetType, Config)forschema. The separateParamsargument no longer exists; type-variable bindings are carried onTargetTypeand accessible viaspectra_type:type_args/1. Update all custom codec modules to the new signatures.
[0.11.4] - 2026-04-20
Added
spectra_transform: a compile-time parse transform that embeds type info directly into a module as an exported__spectra_type_info__/0function. Opt in per module with-compile({parse_transform, spectra_transform}).. This removes the runtimebeam_liboverhead for modules that use it; the existing fallback remains unchanged, so adoption is gradual.
Fixed
#{}(empty-map type) in JSON encode/decode now correctly rejects non-empty maps. Previously it silently accepted and discarded all keys, which caused incorrect union disambiguation — for example, a record's JSON object could decode as#{}instead of the record.
[0.11.3] - 2026-04-19
Fixed
spectra_binary_stringandspectra_stringnow use UTF-8 consistently in both directions when converting between strings and binaries. Previously encode used UTF-8 but decode used raw bytes (latin1), so a non-ASCII value did not roundtrip — e.g. encoding[233](é) produced<<195, 169>>, which decoded back as[195, 169]. Invalid UTF-8 input now returns a structured error instead of silently producing garbage.spectra_json_schemanow emitsanyOfinstead ofoneOffor union types.oneOfrequires exactly one branch to match, which rejected values in overlapping unions (e.g.non_neg_integer() | integer(), where a positive integer matches both branches).anyOfmatches Erlang's union semantics of "matches at least one branch".
Changed
- Expanded property-based test coverage for JSON, string, and binary_string roundtrips and schema validation
[0.11.2] - 2026-04-17
### Changed
- Optimized JSON traversal hot paths for improved performance
### Fixed
- Configured regex module to support Unicode and UCP for pattern constraints
## [0.11.1] - 2026-04-14
Changed
- Optimized JSON traversal performance in
spectra_jsonencoding and decoding - Improved internal consumed keys handling using map matching and list-based structures
[0.11.0] - 2026-04-12
Added
module_types_cacheconfiguration withlocal,persistent, andnonemodes for controlling how module type information is cached.- A shared internal config path so encoding, decoding, schema generation, and OpenAPI generation use the same resolved runtime configuration throughout a call.
Changed
- Breaking: Custom codec callbacks now receive an extra config argument.
encodeanddecodemove from arity 6 to 7, andschemamoves from arity 5 to 6. - Breaking: The old
use_module_types_cacheboolean option is replaced bymodule_types_cache.
[0.10.0] - 2026-04-08
Added
- Elixir struct defaults on decode: When decoding JSON into an Elixir struct type,
Module:__struct__/0is called to retrieve field defaults. Missing JSON fields now use the struct's own default value instead of erroring — matching how Elixir itself handles struct initialisation. A field absent from JSON still errors if its declared type does not allownil/undefinedand the struct's default for that field isnil(i.e. no explicit default was set). onlyfield-filtering in-spectra()attribute: Newonly => [field1, field2]key restricts which fields are included during encoding, decoding, and schema generation — similar to Jason'sonlyoption. Filtering is applied at type-extraction time, so no changes are needed in encode/decode/schema modules. Propagates through union types (e.g.MyStruct | nil) but does not follow user-type or remote-type references.
[0.9.4] - 2026-04-02
Fixed
- OpenAPI component generation bypasses codec
schema/5: When a codec-backed named type or record was referenced as an OpenAPI component viaendpoints_to_openapi, the codec'sschema/5callback was never called — the structural schema was generated instead.
[0.9.3] - 2026-04-01
Added
spectra_type:update_meta/2: New helper that updates a type's metadata map in one call, reducing the boilerplate of pairedget_meta/set_metacalls.make lint: New lint target usingelp lint --rebar --read-config(also added to CI).
Changed
#sp_user_type_ref{}and#sp_remote_type{}internal records now cachearitydirectly, eliminating repeatedlength/1calls across all serialization and deserialization modules.
[0.9.2] - 2026-03-27
Added
spectra_calendar_codec: Built-in codec forcalendar:datetime()andcalendar:date(). Serialises to/from ISO 8601 strings ("YYYY-MM-DDTHH:MM:SS"and"YYYY-MM-DD"). Opt-in via the application environment, same pattern asspectra_dict_codec.
[0.9.1] - 2026-03-26
Fixed
- String/binary constraints (
min_length,max_length,pattern) are now correctly enforced when the type body is a remote type alias that resolves to a string/binary type (e.g. Elixir'sString.t()). Previously the constraints were silently ignored.
[0.9.0] - 2026-03-24
Added
spectra_dict_codec: Built-in codec for encoding and decodingdict:dict()values. Register it via the app env or-behaviour(spectra_codec)like any other codec. Mostly to show that codecs can be implemented for types with arity > 0.
Changed
- Breaking:
spectra_codeccallbacks now receive an additionalSpType :: spectra:sp_type()argument.encodeanddecodeare now arity 6;schemais now arity 5. Existing codec modules must add this argument to all callback clauses. Usespectra_type:type_args/1onSpTypeto access concrete type-variable bindings at the call site.
[0.8.2] - 2026-03-21
Changed
- README: added reference tables documenting all valid
-spectra()attribute keys for types/records and function specs, including thetitlevssummarydistinction.
[0.8.1] - 2026-03-21
Added
- Exported OpenAPI types:
spectra_openapinow exportsendpoint_spec/0,endpoint_doc/0,response_spec/0,parameter_spec/0,parameter_input_spec/0,http_method/0,http_status_code/0, andopenapi_metadata/0. parameter_input_spec/0: New type for the map passed towith_parameter/3. Distinct from the internalparameter_spec/0(which includesmodule) — the function mergesmodulein automatically.
Changed
- README overhauled: simpler introductory example, cleaner API reference, restructured Custom Codecs section, added
binary_string/stringformat example.
[0.8.0] - 2026-03-19
Added
- Custom codecs: New
spectra_codecbehaviour withencode/4,decode/4, and optionalschema/4callbacks. Register codecs via the application environment ({spectra, [{codecs, #{...}}]}) or by declaring-behaviour(spectra_codec)on the type's own module. - Type parameters: Types can now carry a
type_parametersfield in their-spectra()attribute. The value is passed as the 4th argument to codec callbacks, allowing a single codec module to handle multiple parameterised variants. - Auto-populate
descriptionanddeprecatedfrom type annotations: Parameters, request bodies, and response headers that reference a type with a-spectra()doc annotation now automatically inheritdescriptionanddeprecated. Explicit values on the spec still take precedence. - Plain atom type refs in
spectra_openapi:spectra_openapifunctions now accept plain atoms as type references (e.g.userinstead of{type, user, 0}), matching the behaviour ofspectra.erl.
Changed
- Breaking:
with_request_body/4fourth argument changed from an opts map (#{content_type => ..., description => ...}) to a plaincontent_typebinary. Passdescriptionvia the type's-spectra()annotation instead.
Fixed
type_doc/2now follows type references: The internaltype_doc/2function inspectra_openapipreviously returned an empty description whenever the resolved type was an#sp_user_type_ref{}or#sp_remote_type{}. It now follows the reference to the underlying type to retrieve its description. Local annotations on the alias take precedence — the reference is only followed when the alias itself carries no-spectradoc.
[0.7.0] - 2026-03-04
Added
descriptionanddeprecatedfields for OpenAPI parameters:parameter_spec()now acceptsdescription => binary()anddeprecated => boolean()fields, propagated into the generated OpenAPI output.descriptionfor request body specs:request_body_spec()now accepts adescriptionfield.deprecatedfor response header specs:header_spec()now accepts adeprecated => boolean()field.- Extended
openapi_metadata(): Supports additionalinfofields and a top-levelserverslist for multi-server OpenAPI documents.
Changed
- Breaking:
with_request_body/3,4now takes the schema as the third positional argument. Optional metadata (content_type,description) is passed as a fourthOptsmap. Update calls fromwith_request_body(E, Method, #{schema => S})towith_request_body(E, Method, S).
[0.6.0] - 2026-03-04
Added
-spectraattribute for function specs: You can now annotate-specdeclarations with a-spectra()attribute to attach metadata to functions. Thefunction_doc()type supportssummary,description, anddeprecatedfields (distinct from thetype_doc()fields used for types and records).
Fixed
#sp_union{}typesfield was declared with a default value instead of a type annotation, which could cause subtle runtime issues.
[0.5.1] - 2026-03-02
Added
pre_decoded/pre_encodedoptions fordecode/5andencode/5: pass[pre_decoded]to skip JSON parsing when your input is already a decoded term, or[pre_encoded]to get back ajson:encode_value()term instead ofiodata()fromencode/5.spectra_openapi:endpoints_to_openapi/3: new overload that accepts encode options (e.g.[pre_encoded]) for the generated OpenAPI document.
Changed
__spectra_type_info__/0calls are now cached inpersistent_termalongside abstract-code lookups, reducing repeated reflection overhead.
[0.5.0] - 2026-02-26
Added
- JSON schema documentation: Types can now carry
titleanddescriptionmetadata via thespectraattribute, which is propagated into generated JSON Schema and OpenAPI output __spectra_type_info__/0protocol: Modules can now expose itstype_infoby exporting the__spectra_type_info__/0function. This is an implementation detail in the library. It will be used to pair documentation with types in Elixir, and can later be used for performance and to handle hot code reloading better.
[0.4.0] - 2026-01-27
Changed
- Breaking:
spectra:schema/3now returns schema values directly instead of{ok, Schema}or{error, Reason}tuples.
[0.3.2] - 2026-01-25
Changed
- Improved documentation and clarified OTP 27 requirement
[0.3.0] - 2026-01-20
Changed
- Upgraded JSON Schema from draft-07 to 2020-12 specification with proper
$schemafield support - Upgraded OpenAPI spec generation from 3.0 to 3.1 (which natively uses JSON Schema 2020-12)
- Improved remote type handling in enums and parameterized types
- Simplified error handling implementation in preparation for better error messages
- Enhanced null/optional handling with clearer documentation and dedicated tests for undefined/nil behavior in mandatory vs optional map fields
Internal
- Refactored type utilities into
spectra_util.erlwith renamed functions for consistency - New tests for typed map fields, parameterized remote types, and enum remote types
- Property-based testing for JSON encoding/schema/decoding consistency (
test/prop_json_encode_schema_consistency.erl) - Python validators for JSON Schema 2020-12 and OpenAPI 3.1 standards compliance
- Development tooling improvements including updated
.tool-versionsand enhancedMakefilewith release safeguards - Major code simplification in
spectra_binary_string.erl,spectra_json.erl, andspectra_string.erl - Created
sp_error.erlmodule for consolidated error handling
[0.2.0] - 2025-12-14
Changed
- Breaking: Extra fields in JSON objects are now ignored during deserialization instead of causing a
not_matched_fieldserror. This affects map, struct (elixir) and record deserialization.
Notes
- The old strict validation behavior has been commented out with a TODO to potentially add it back as a configuration option in the future