Skip to content

Add asyncapi mqtt bindings - #12

Merged
mlilback merged 12 commits into
mlilback:mainfrom
pureions:mqtt-bindings
Jul 23, 2026
Merged

mlilback merged 12 commits into
mlilback:mainfrom
pureions:mqtt-bindings

Conversation

@pureions

Copy link
Copy Markdown
Contributor

This partially fixes #11 and adds models and macro parsing for mqtt bindings.

The documentation about operation bindings of mqtt are a bit unclear. The examples include the bindings into the channel. I put them into the operation. I'm not sure what's correct.

@mlilback mlilback left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tackling this — MQTT bindings are a genuinely wanted feature (#11), and the attribute-parsing layer here is well-structured. However, I can't merge as-is: the code-generation layer doesn't compile when the feature is actually used. The added tests only exercise the extract_* parsing functions, so CI stays green, but no test derives a type with mqtt(...) and checks the emitted code. I confirmed by writing a small example that uses the server/operation/message MQTT attributes — it produces 9 compile errors.

Blocking — codegen emits uncompilable tokens (asyncapi-rust-codegen/src/lib.rs):

  1. Nested quote! in generated code (server last_will): emits topic: quote! { #topic.to_string() } into the user's crate → expected expression, found '.' and cannot find macro quote. Should be topic: #topic.to_string() (same for qos/retain/message).
  2. Wrong type name: references asyncapi_rust::LastWill, but the model defines MqttLastWill → E0422.
  3. Nonexistent field: sets client_session: on MqttServerBindings, whose field is clean_session → E0560.
  4. Type mismatch on clean_session: generates Some(#s.to_string()) (String) for an Option<bool> field → E0308.
  5. Internal path leaked into user code: message response_topic emits crate::asyncapi_attrs::ResponseTopic::Uri(...) — that module is codegen-internal and invisible to the user crate, and the model field is typed Schema, not ResponseTopic → E0433 + type mismatch.

Blocking — breaking change + failing doctests:

  • Adding the required bindings field to Server, Operation, and Message breaks the doctests in asyncapi-rust-models/src/lib.rs (cargo test fails with 4× E0063 missing field bindings), and it's a breaking change for anyone constructing these structs literally. Please fix all doctests; ideally make the field non-breaking (e.g. #[serde(default)] + Default).

Should fix:

  • serde typo: MqttServerBindings.client_id uses rename = "cliendId" — the JSON key should be clientId. This would emit wrong output silently even once codegen compiles.
  • Parsed-but-dropped fields: correlation_data (message), maximum_packet_size (server), and the response_topic::Reference variant are parsed but never emitted (hardcoded None / ignored). Either wire them through or drop them for now — the #[allow(unused)] markers hint these are half-finished.

Please add: an integration/trybuild test (or an example under examples/) that actually derives a type with mqtt(...) on a server, operation, and message and asserts the generated spec. A single such test would have caught every issue above.

One design note: your PR description asks about operation vs. channel placement for qos/retain/messageExpiryInterval — putting them on the operation is correct per the AsyncAPI MQTT binding spec, so that choice is good.

Happy to help once these are addressed.

@pureions

pureions commented Jul 13, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks for your review! I addressed your points. Pls let me know if this is fine or if further changes are needed.

Update: Reading my code again I noticed that I'm still missing proper derives for session_expiry_interval and some other properties. I will update that in my next commit.

@mlilback
mlilback dismissed their stale review July 15, 2026 00:32

Superseded — the earlier blocking items are all resolved. Filing a fresh review with the one remaining request.

@mlilback mlilback left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the follow-up — this is exactly what I was after. I pulled the branch and verified everything:

  • cargo build --workspace, cargo test --workspace (incl. all 12 model doctests), and cargo clippy --workspace --examples are all clean.
  • The new examples/mqtt_bindings.rs compiles and runs, emitting correct server/operation/message MQTT bindings — that's the regression the original codegen couldn't survive, so this is solid.
  • Every blocking item is resolved: the nested quote!, the MqttLastWill / clean_session fixes, the clientId serde key, the responseTopic now emitting the public model type instead of the internal *Meta path, and correlation_data / maximum_packet_size are now wired through rather than dropped. Nicely done.

One small thing before I merge: the public type is misspelled MqttReponseTopic (missing the "s" — should be MqttResponseTopic). Since it's part of the public API, I'd like to fix it now rather than after a release. It appears in 4 places:

  • asyncapi-rust-models/src/lib.rs:543 — the pub enum MqttReponseTopic definition
  • asyncapi-rust-models/src/lib.rs:570 — the response_topic: Option<MqttReponseTopic> field
  • asyncapi-rust-codegen/src/lib.rs:352 and :359 — the two asyncapi_rust::MqttReponseTopic::… emissions

A quick MqttReponseTopic → MqttResponseTopic rename across those (the JSON output key responseTopic is already correct, so no serialized-output change). Once that's pushed I'll squash-merge. Thanks again for sticking with this — MQTT bindings are a great addition.

@pureions

Copy link
Copy Markdown
Contributor Author

Thanks again! I renamed the struct.

@mlilback
mlilback dismissed their stale review July 23, 2026 00:21

Rename landed in 259c521 — all requested changes addressed. Approving.

@mlilback mlilback left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All requested changes are in as of 259c521. Verified locally: workspace builds, full test suite passes (unit + integration + all 12 doctests), clippy is clean, and examples/mqtt_bindings.rs compiles and runs, emitting correct server/operation/message MQTT bindings. The MqttReponseTopic → MqttResponseTopic rename is complete across all four sites. Thanks for the thorough follow-through — merging via squash. 🎉

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds MQTT protocol-specific bindings support to asyncapi-rust by extending the public AsyncAPI models and teaching the proc-macros to parse and emit MQTT binding objects for messages, servers, and operations, plus providing an example showcasing the new attributes.

Changes:

  • Extend asyncapi-rust-models with MQTT binding model types and add bindings fields to Server, Message, and Operation.
  • Update asyncapi-rust-codegen macro parsing and code generation to support mqtt(...) bindings for messages, servers, and operations (including schema-or-number values).
  • Add a new mqtt_bindings example and update the existing chat_api example to compile with the new bindings fields.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
asyncapi-rust/examples/mqtt_bindings.rs New example demonstrating MQTT message/server/operation binding attributes and printing the generated spec.
asyncapi-rust/examples/chat_api.rs Adds bindings: None to keep the example compiling after the new model fields.
asyncapi-rust-models/src/lib.rs Introduces MQTT bindings model types and adds bindings to core spec structs (Server, Message, Operation).
asyncapi-rust-codegen/src/lib.rs Generates MQTT binding objects into the produced AsyncApiSpec for messages/servers/operations.
asyncapi-rust-codegen/src/asyncapi_spec_attrs.rs Parses mqtt(...) bindings inside #[asyncapi_server] and #[asyncapi_operation].
asyncapi-rust-codegen/src/asyncapi_attrs.rs Parses mqtt(...) bindings inside #[asyncapi(...)] for ToAsyncApiMessage (message bindings).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread asyncapi-rust/examples/mqtt_bindings.rs Outdated
Comment thread asyncapi-rust/examples/mqtt_bindings.rs Outdated
Comment thread asyncapi-rust/examples/mqtt_bindings.rs Outdated
Comment thread asyncapi-rust/examples/mqtt_bindings.rs Outdated
Comment thread asyncapi-rust-codegen/src/asyncapi_spec_attrs.rs
Comment thread asyncapi-rust-models/src/lib.rs Outdated
@codecov-commenter

Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

Thanks for integrating Codecov - We've got you covered ☂️

- Remove redundant & in example println! args (clippy -D warnings)
- Add missing comma after maximum_packet_size in server mqtt(...) attr
- Avoid unwrap() panics in example; print bindings safely with and_then
- Fix stale comment referencing ChatMessage/SystemMessage
- Fix duplicated word in MqttResponseTopic::Schema doc comment

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Comment thread asyncapi-rust/examples/mqtt_bindings.rs Outdated
Comment thread asyncapi-rust-codegen/src/lib.rs
- Add tests/mqtt_bindings_integration.rs deriving mqtt(...) on a server,
  operation, and message and asserting spec.{servers,operations,
  components.messages}[..].bindings.mqtt (closes the assertion gap noted
  in review; the example only prints and unit tests only cover parsing)
- Model example ExampleResponseTopic as a transparent String newtype so
  the MQTT responseTopic emits a string schema, not an object; anchor the
  pattern and fix the [a-z1-9] -> [a-z0-9] class
@mlilback
mlilback merged commit 00e6429 into mlilback:main Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add protocol specific bindings

4 participants