Repository navigation
Add asyncapi mqtt bindings - #12
Conversation
mlilback
left a comment
There was a problem hiding this comment.
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):
- Nested
quote!in generated code (serverlast_will): emitstopic: quote! { #topic.to_string() }into the user's crate →expected expression, found '.'andcannot find macro quote. Should betopic: #topic.to_string()(same forqos/retain/message). - Wrong type name: references
asyncapi_rust::LastWill, but the model definesMqttLastWill→E0422. - Nonexistent field: sets
client_session:onMqttServerBindings, whose field isclean_session→E0560. - Type mismatch on
clean_session: generatesSome(#s.to_string())(String) for anOption<bool>field →E0308. - Internal path leaked into user code: message
response_topicemitscrate::asyncapi_attrs::ResponseTopic::Uri(...)— that module is codegen-internal and invisible to the user crate, and the model field is typedSchema, notResponseTopic→E0433+ type mismatch.
Blocking — breaking change + failing doctests:
- Adding the required
bindingsfield toServer,Operation, andMessagebreaks the doctests inasyncapi-rust-models/src/lib.rs(cargo testfails 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_idusesrename = "cliendId"— the JSON key should beclientId. This would emit wrong output silently even once codegen compiles. - Parsed-but-dropped fields:
correlation_data(message),maximum_packet_size(server), and theresponse_topic::Referencevariant are parsed but never emitted (hardcodedNone/ 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.
|
Thanks for your review! I addressed your points. Pls let me know if this is fine or if further changes are needed.
|
Superseded — the earlier blocking items are all resolved. Filing a fresh review with the one remaining request.
mlilback
left a comment
There was a problem hiding this comment.
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), andcargo clippy --workspace --examplesare all clean.- The new
examples/mqtt_bindings.rscompiles 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!, theMqttLastWill/clean_sessionfixes, theclientIdserde key, theresponseTopicnow emitting the public model type instead of the internal*Metapath, andcorrelation_data/maximum_packet_sizeare 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— thepub enum MqttReponseTopicdefinitionasyncapi-rust-models/src/lib.rs:570— theresponse_topic: Option<MqttReponseTopic>fieldasyncapi-rust-codegen/src/lib.rs:352and:359— the twoasyncapi_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.
|
Thanks again! I renamed the struct. |
Rename landed in 259c521 — all requested changes addressed. Approving.
mlilback
left a comment
There was a problem hiding this comment.
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. 🎉
There was a problem hiding this comment.
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-modelswith MQTT binding model types and addbindingsfields toServer,Message, andOperation. - Update
asyncapi-rust-codegenmacro parsing and code generation to supportmqtt(...)bindings for messages, servers, and operations (including schema-or-number values). - Add a new
mqtt_bindingsexample and update the existingchat_apiexample to compile with the newbindingsfields.
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.
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
- 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
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.