Skip to content

Releases: mlilback/asyncapi-rust

v0.5.0 — MQTT Protocol Bindings

Choose a tag to compare

@mlilback mlilback released this 24 Jul 13:42

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, and binding_version.

🐛 Bug Fixes

  • Malformed #[asyncapi(...)] / mqtt(...) attributes now fail fast with a compile error instead of being silently dropped (#14). Previously a last_will missing 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

  • @pureions (Max Christoph) made their first contribution in #12 — thank you! 🎉

Full Changelog: v0.4.0...v0.5.0

v0.4.0

Choose a tag to compare

@mlilback mlilback released this 19 Jun 22:07

[0.4.0] - 2026-06-19

🐛 Bug Fixes

  • Replace HashMap with IndexMap for deterministic spec output (closes #9) (#9)

📚 Documentation

  • Add 0.3.x → 0.4.0 migration guide and update version references

v0.3.0

Choose a tag to compare

@mlilback mlilback released this 19 Jun 16:59

[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

v0.3.0-beta.3 Pre-release
Pre-release

Choose a tag to compare

@mlilback mlilback released this 19 Jun 00:55

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

v0.3.0-beta.2 Pre-release
Pre-release

Choose a tag to compare

@mlilback mlilback released this 19 Jun 00:32

Bug Fixes

  • Hoist shared $defs into components.schemas; rewrite payload $refs (#7)

    Previously (beta.1) shared sub-type definitions were embedded as a full $defs block in every message payload, causing downstream code generators to emit each shared type once per message. Now:

    • components.schemas is populated with each shared type exactly once
    • Message payloads contain no $defs block
    • All $refs in payloads point to #/components/schemas/X instead of #/$defs/X
    • New asyncapi_schemas() method on ToAsyncApiMessage types 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

  • Parameter object now conforms to AsyncAPI 3.0 — schema_type/format replaced with default, enum_values, examples, location (#5, reported by @pureions)
  • No more panic on enums containing serde_json::Value fields (#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

v0.3.0-beta.1 Pre-release
Pre-release

Choose a tag to compare

@mlilback mlilback released this 19 Jun 00:08

Bug Fixes

  • Bring Parameter object into AsyncAPI 3.0 compliance — schema_type/format replaced with default, enum_values, examples, location (reported by @pureions, #5)
  • ToAsyncApiMessage no longer panics on enums containing serde_json::Value fields (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 any serde(tag = "...") field name, not just "type". Shared $defs are 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

Choose a tag to compare

@mlilback mlilback released this 07 Nov 17:18

[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

Choose a tag to compare

@mlilback mlilback released this 06 Nov 19:41

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 crate Cargo.toml files
  • No code changes from v0.1.0

All three crates now display the complete README on their crates.io pages:

Documentation is automatically built at:

Full Changelog: v0.1.0...v0.1.1

v0.1.0 - Initial MVP Release

Choose a tag to compare

@mlilback mlilback released this 06 Nov 17:19

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_binary attribute 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

📖 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

  1. simple.rs - Basic message types
  2. chat_api.rs - Complete spec
  3. asyncapi_derive.rs - AsyncApi derive usage
  4. generate_spec_file.rs - File generation
  5. full_asyncapi_derive.rs - All features
  6. message_integration.rs - Message integration
  7. actix_websocket.rs - actix-web integration
  8. axum_websocket.rs - axum integration
  9. framework_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