Repository navigation
Releases: mlilback/asyncapi-rust
Release list
v0.5.0 — MQTT Protocol Bindings
Highlights
0.5.0 adds protocol bindings to asyncapi-rust, starting with MQTT. You can now declare MQTT server, operation, and message bindings directly in your derive attributes, and they flow through to the generated AsyncAPI 3.0 spec.
#[asyncapi_server(
name = "production",
host = "mqtt.example.com",
protocol = "mqtt",
mqtt(client_id = "svc", clean_session = false, keep_alive = 60)
)]
#[asyncapi_operation(
name = "publishReading", action = "send", channel = "sensors",
mqtt(qos = 2, retain = true, message_expiry_interval = 300)
)]See examples/mqtt_bindings.rs for a full server/operation/message example.
⚡ Features
- MQTT protocol bindings for servers, operations, and messages (#12, partially addresses #11). Covers
client_id,clean_session,keep_alive,session_expiry_interval,maximum_packet_size,last_will,qos,retain,message_expiry_interval,payload_format_indicator,content_type,response_topic,correlation_data, andbinding_version.
🐛 Bug Fixes
- Malformed
#[asyncapi(...)]/mqtt(...)attributes now fail fast with a compile error instead of being silently dropped (#14). Previously alast_willmissing a required sub-field, or a value of the wrong literal type, was swallowed.
⚠️ Breaking change / Migration
Server, Operation, and Message each gained a bindings field. It is Option<_> with #[serde(default)] and Default, so deserialization, ..Default::default(), and read-only access are unaffected.
If you construct any of these structs with an explicit struct literal (e.g. in tests or a custom spec builder), add the new field:
let server = asyncapi_rust::Server {
// ...existing fields...
bindings: None,
};See the "Migrating from 0.4.x" section in the README for details.
New Contributors
Full Changelog: v0.4.0...v0.5.0
v0.4.0
v0.3.0
[0.3.0] - 2026-06-19
📚 Documentation
- Update README for 0.3.0 and regenerate CHANGELOG
- Remove early development notice from README
- Update channel parameter docs to reflect AsyncAPI 3.0 Parameter fields
🧪 Testing
- Expand coverage to ~98% and add CI coverage reporting
🐛 Bug Fixes
-
Use variant ident as message name; add message_name override; detect collisions (closes #8) (reported by @mlilback, #8)
-
Hoist shared $defs into components.schemas; rewrite payload $refs (closes #7) (#7, #6)
-
Resolve clippy warnings in examples
-
Bring Parameter object into AsyncAPI 3.0 compliance (closes #5) (reported by @pureions, #5)
-
Handle open-ended JSON Schemas (e.g. serde_json::Value) without panic (closes #4) (reported by @csells, #4)
-
Emit per-variant payload schema for tagged enums; embed $defs (closes #6, closes #2) (#6, #2, #2)
v0.3.0-beta.3
Changes in beta.3
Fix: message name collisions and empty serde rename (#8)
Breaking change from beta.2: message names in components.messages and asyncapi_message_names() now use the Rust variant identifier (e.g. CurrentEditor) rather than the serde rename string (e.g. "current-editor"). The serde rename is preserved as the wire discriminant inside each variant's payload schema.
Why: serde rename strings are wire-format values — they can be empty, contain dots and hyphens, and are not unique across multiple enums. Using variant identifiers produces stable, code-generation-friendly names.
New attribute: #[asyncapi(message_name = "CustomName")] on a variant overrides the default (variant ident). Use this to disambiguate when two enums share a variant identifier (e.g. OperationResponse::GetInfo → message_name = "GetInfoResponse").
Collision detection: AsyncApi derive now panics at runtime with a clear message if two message types produce the same message name, instead of silently overwriting one.
Migration from beta.2: update any code that looks up messages by serde rename key (e.g. messages.get("user.join")) to use the variant ident (messages.get("UserJoin")), or add #[asyncapi(message_name = "user.join")] to restore the old name.
Dependency
asyncapi-rust = { git = "https://github.com/mlilback/asyncapi-rust", tag = "v0.3.0-beta.3" }v0.3.0-beta.2
Bug Fixes
-
Hoist shared
$defsintocomponents.schemas; rewrite payload$refs (#7)Previously (beta.1) shared sub-type definitions were embedded as a full
$defsblock in every message payload, causing downstream code generators to emit each shared type once per message. Now:components.schemasis populated with each shared type exactly once- Message payloads contain no
$defsblock - All
$refs in payloads point to#/components/schemas/Xinstead of#/$defs/X - New
asyncapi_schemas()method onToAsyncApiMessagetypes exposes the shared definitions for custom consumers
Testing this beta
asyncapi-rust = { git = "https://github.com/mlilback/asyncapi-rust", tag = "v0.3.0-beta.2" }What's in 0.3.0 so far
Parameterobject now conforms to AsyncAPI 3.0 —schema_type/formatreplaced withdefault,enum_values,examples,location(#5, reported by @pureions)- No more panic on enums containing
serde_json::Valuefields (#4, reported by @csells) - Per-variant payload schemas for tagged enums; works with any
serde(tag)field name (#6, #2) - Shared sub-types hoisted to
components.schemas(#7)
v0.3.0-beta.1
Bug Fixes
- Bring
Parameterobject into AsyncAPI 3.0 compliance —schema_type/formatreplaced withdefault,enum_values,examples,location(reported by @pureions, #5) ToAsyncApiMessageno longer panics on enums containingserde_json::Valuefields (reported by @csells, #4)- Per-variant payload schema for tagged enums — each message now carries only its own variant schema instead of the whole-enum
oneOf. Works with anyserde(tag = "...")field name, not just"type". Shared$defsare embedded per-variant for self-contained payloads. (#6, #2)
Breaking Changes
#[asyncapi_channel(...)] parameter attributes no longer accept schema_type or format (removed from the AsyncAPI 3.0 Parameter object). Use examples, default, enum_values, or location instead.
Testing this beta
Add to your Cargo.toml:
asyncapi-rust = { git = "https://github.com/mlilback/asyncapi-rust", tag = "v0.3.0-beta.1" }v0.2.0
[0.2.0] - 2025-11-07
⚙️ Miscellaneous
- Fix rustfmt formatting issues
- Add git-cliff for changelog generation
⚡ Features
- Add server variables and channel parameters support
🐛 Bug Fixes
- Support module paths in #[asyncapi_messages(...)]
- Support schemars 1.1 schema type arrays for optional fields
📚 Documentation
- Generate retroactive CHANGELOG.md for v0.1.0 and v0.1.1
- Add server_variables.rs example
v0.1.1 - README metadata fix
Version 0.1.1
This is a metadata-only release to fix the missing README on crates.io package pages.
Changes
- Added
readme = "../README.md"to all three crateCargo.tomlfiles - No code changes from v0.1.0
All three crates now display the complete README on their crates.io pages:
- https://crates.io/crates/asyncapi-rust
- https://crates.io/crates/asyncapi-rust-codegen
- https://crates.io/crates/asyncapi-rust-models
Documentation is automatically built at:
- https://docs.rs/asyncapi-rust
- https://docs.rs/asyncapi-rust-codegen
- https://docs.rs/asyncapi-rust-models
Full Changelog: v0.1.0...v0.1.1
v0.1.0 - Initial MVP Release
AsyncAPI 3.0 Specification Generation for Rust
Generate AsyncAPI documentation directly from your Rust code using procedural macros.
✨ Features
#[derive(ToAsyncApiMessage)]- Generate message metadata and JSON schemas from Rust types#[derive(AsyncApi)]- Generate complete AsyncAPI specifications#[asyncapi_messages(...)]- Automatically integrate message types into specs- Full schemars integration - JSON Schema generation from Rust types
- Server, channel, and operation definitions - Complete AsyncAPI 3.0 support
- Binary protocol support -
triggers_binaryattribute for binary messages - Framework integration - Examples for actix-ws, axum, and tungstenite
- 9 comprehensive examples - From simple to real-world usage
- Complete documentation - Full rustdoc on docs.rs
🚀 Getting Started
Add to your `Cargo.toml`:
```toml
[dependencies]
asyncapi-rust = "0.1"
serde = { version = "1.0", features = ["derive"] }
schemars = { version = "0.8", features = ["derive"] }
```
Quick example:
```rust
use asyncapi_rust::{AsyncApi, ToAsyncApiMessage, schemars::JsonSchema};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, JsonSchema, ToAsyncApiMessage)]
#[serde(tag = "type")]
pub enum ChatMessage {
#[serde(rename = "user.join")]
UserJoin { username: String, room: String },
}
#[derive(AsyncApi)]
#[asyncapi(title = "Chat API", version = "1.0.0")]
#[asyncapi_messages(ChatMessage)]
struct ChatApi;
```
📦 Published Crates
- asyncapi-rust - Main crate
- asyncapi-rust-codegen - Proc macros
- asyncapi-rust-models - Runtime models
📖 Documentation
🎯 What's Included
Core Functionality
- Message metadata generation from Rust types
- JSON Schema generation via schemars
- Complete AsyncAPI 3.0 spec generation
- Automatic message integration into specs
- serde attribute support (rename, tag, etc.)
Advanced Features
- Binary protocol support
- Server definitions
- Channel definitions
- Operation definitions (send/receive)
- Helper attributes for documentation
Examples
simple.rs- Basic message typeschat_api.rs- Complete specasyncapi_derive.rs- AsyncApi derive usagegenerate_spec_file.rs- File generationfull_asyncapi_derive.rs- All featuresmessage_integration.rs- Message integrationactix_websocket.rs- actix-web integrationaxum_websocket.rs- axum integrationframework_integration_guide.rs- Framework guide
🧪 Testing
- 20 unit tests
- 11 integration tests
- 10 documentation tests
- Clippy clean
- MSRV: Rust 1.85
📝 Release Notes
This is the initial MVP release with complete functionality for generating AsyncAPI 3.0 specifications from Rust code. The API is not yet stable and may change in future releases.
Key Additions in This Release
- Complete AsyncAPI 3.0 models
- ToAsyncApiMessage derive macro
- AsyncApi derive macro
- Message integration with #[asyncapi_messages(...)]
- Full schemars integration
- Comprehensive documentation
- Real-world framework examples
🙏 Acknowledgments
Inspired by utoipa for OpenAPI generation and the AsyncAPI Initiative.
License: MIT OR Apache-2.0
Author: Mark Lilback