Skip to content
Merged
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 74 additions & 64 deletions apps/generator/docs/generator-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Suppose you can only sleep when the AC in your bedroom is set to 22 °C, and you

In this tutorial:

- You'll use the [Eclipse Mosquito](https://test.mosquitto.org) **MQTT broker**, which you'll connect to subscribe and publish messages using an MQTT client.
- You'll use the [Eclipse Mosquitto](https://test.mosquitto.org) **MQTT broker**, which you'll connect to subscribe and publish messages using an MQTT client.
- You'll use [Python Paho-MQTT](https://pypi.org/project/paho-mqtt/) as the **MQTT client** in this project.
- You'll create a React template that will use the MQTT broker to allow you to monitor your bedroom's temperature and notify you when the temperature drops or rises above 22 °C.
- Lastly, create a reusable component for the output code's `sendTemperatureDrop` and `sendTemperatureRise` functions.
Expand Down Expand Up @@ -44,7 +44,7 @@ Before you create the template, you'll need to have an [AsyncAPI document](https

``` yml

asyncapi: 2.6.0
asyncapi: 3.0.0

info:
title: Temperature Service
Expand All @@ -53,22 +53,26 @@ info:

servers:
dev:
url: test.mosquitto.org #in case you're using local mosquitto instance, change this value to localhost.
host: test.mosquitto.org #in case you're using local mosquitto instance, change this value to localhost.
protocol: mqtt

channels:
temperature/changed:
description: Updates the bedroom temperature in the database when the temperatures drops or goes up.
publish:
operationId: temperatureChange
message:
temperatureChanged:
address: temperature/changed
messages:
temperatureChange:
description: Message that is being sent when the temperature in the bedroom changes.
payload:
type: object
additionalProperties: false
properties:
temperatureId:
type: string
$ref: '#/components/schemas/temperatureId'
description: Updates the bedroom temperature in the database when the temperatures drops or goes up.

operations:
temperatureChange:
action: receive
summary: Message sent to the broker when the temperature is changed.
channel:
$ref: '#/channels/temperatureChanged'

components:
schemas:
temperatureId:
Expand Down Expand Up @@ -112,8 +116,8 @@ The **package.json** file is used to define the dependencies for your template.
"version": "0.0.1",
"description": "A template that generates a Python MQTT client using MQTT.",
"generator": {
"apiVersion": "v1",
"generator": ">=1.10.0 <2.0.0",
"apiVersion": "v3",
"generator": ">=1.10.0 <=3.0.1",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

AsyncAPI generator v3 API compatibility version requirements

💡 Result:

Short answer: Templates must declare apiVersion: "v3" in their generator configuration so the AsyncAPI Generator will use the Parser-API/Parser v3 runtime and accept AsyncAPI spec v3 documents. If a template omits or uses a non‑v3 apiVersion the Generator assumes older Parser-API behavior and will error (e.g., "Version '3.0.0' is not supported"). Also check the template's declared supported generator range (generator field) to ensure the template is compatible with your @asyncapi/generator version. [1][2][3]

Example (package.json or .ageneratorrc): include "apiVersion": "v3" under the generator config. [1][3]

Sources:

  • AsyncAPI generator configuration documentation. [1]
  • Generator version vs template version / compatibility checks. [2]
  • Community example explaining setting apiVersion to "v3" to fix the error. [3]

🏁 Script executed:

# Search for AsyncAPI generator version information and v3 compatibility
rg -i "generator.*version|apiVersion.*v3|v3.*compatibility|changelog|release" --type=md --type=json -A 2 -B 2

Repository: asyncapi/generator

Length of output: 37640


🏁 Script executed:

# Search for v3 API introduction in CHANGELOG
rg -A 5 -B 5 "v3.*API|Parser.*v3|apiVersion.*v3" apps/generator/CHANGELOG.md --type=md | head -100

# Look for generator version requirements and v3 compatibility mentions
rg "generator.*1\.\d+\.\d+|v3" apps/generator/docs/configuration-file.md -A 2 -B 2 --type=md

Repository: asyncapi/generator

Length of output: 4186


🏁 Script executed:

# Check if there's a specific release note about v3 support
rg -i "v3 parser|parser-api|apiVersion" apps/generator/CHANGELOG.md -C 5 --type=md | grep -A 10 -B 10 "v3"

Repository: asyncapi/generator

Length of output: 708


🏁 Script executed:

# Search CHANGELOG more comprehensively for v3 support introduction
rg "v3|1\.3\.0|1\.10\.0" apps/generator/CHANGELOG.md -B 5 -A 5 | head -150

Repository: asyncapi/generator

Length of output: 739


🏁 Script executed:

# Check the generator-template.md file specifically to see all version references
grep -n "generator.*1\." apps/generator/docs/generator-template.md

Repository: asyncapi/generator

Length of output: 147


🏁 Script executed:

# Search for when v3 API support was introduced in CHANGELOG
rg "Parser.*API.*v3|v3.*Parser|apiVersion.*v3" apps/generator/CHANGELOG.md -B 10 -A 10 | head -200

Repository: asyncapi/generator

Length of output: 1210


🏁 Script executed:

# Look at actual package.json or configuration files in the repo to understand v3 requirements
fd "package.json" apps/generator/docs -o apps/generator/test | xargs grep -l "apiVersion" | head -5

Repository: asyncapi/generator

Length of output: 219


🏁 Script executed:

# Check if there are any test templates or examples with v3 that show the actual minimum version needed
find apps/generator -name "*.json" -o -name "*.yaml" -o -name ".ageneratorrc" | xargs grep -h "apiVersion.*v3" -A 1 -B 1 2>/dev/null | sort | uniq

Repository: asyncapi/generator

Length of output: 83


🏁 Script executed:

# Check the entire generator-template.md file context around those lines
sed -n '115,125p' apps/generator/docs/generator-template.md
sed -n '330,340p' apps/generator/docs/generator-template.md

Repository: asyncapi/generator

Length of output: 735


🏁 Script executed:

# Look for any documentation or changelog entries explaining why this template has a different version range
rg "1\.10\.0|3\.0\.1" apps/generator/ --type=md --type=json

Repository: asyncapi/generator

Length of output: 1277


🏁 Script executed:

# Check the generator changelog for v3 introduction
rg "## 3\." apps/generator/CHANGELOG.md -A 20 | head -80

Repository: asyncapi/generator

Length of output: 1376


🏁 Script executed:

# Look for v3 API first appearance in CHANGELOG
rg "v3|Parser.*API" apps/generator/CHANGELOG.md | head -20

Repository: asyncapi/generator

Length of output: 104


🏁 Script executed:

# Check the exact context of both occurrences in generator-template.md
cat -n apps/generator/docs/generator-template.md | sed -n '115,340p'

Repository: asyncapi/generator

Length of output: 11051


🌐 Web query:

AsyncAPI generator v3 API support minimum version 1.3.0 1.10.0 documentation

💡 Result:

I’m missing context—do you want (a) the AsyncAPI Generator v3 release/docs that state minimum supported AsyncAPI spec versions (e.g., 1.3.0 vs 1.10.0), (b) instructions for installing Generator v3 with a minimum dependency version, or (c) links to the specific AsyncAPI docs/pages? Which exactly do you want?


🌐 Web query:

AsyncAPI parser API v3 template compatibility generator version requirements

💡 Result:

Short answer

  • To use Parser API v3 in a template, set apiVersion: "v3" in the template config (package.json "generator" property or .ageneratorrc). [1]
  • The template must also declare a generator semver range it’s compatible with (the "generator" field) so the Generator CLI can validate compatibility. Use a Generator version that supports passing Parser v3 (use the Generator/CLI release that provides the new parser or run the CLI with the new-generator option if documented). [1][2]
  • Example fix (package.json generator section): "apiVersion": "v3". This is the recommended way to make the Generator use parser-js v3 for AsyncAPI v3 specs. [3]

Sources

  • Template configuration (apiVersion, generator compatibility, .ageneratorrc / package.json). [1]
  • Generator vs template versioning and how generator validates template "generator" ranges; note about using the newer generator/CLI. [2]
  • Community example showing setting apiVersion: "v3" to enable parser v3. [3]

Update generator version range to match documentation standard.

The apiVersion: v3 is correct for v3 Parser API support. However, the generator version range should be >=1.3.0 <3.0.0 to align with official template documentation. The current range >=1.10.0 <=3.0.1 is unnecessarily restrictive on the lower bound and uses an incorrect upper bound pattern (inclusive patch version instead of exclusive major version).

🤖 Prompt for AI Agents
In @apps/generator/docs/generator-template.md around lines 119 - 120, The
generator version range in the template is incorrect: update the "generator"
field to use the documented range format by changing its value from ">=1.10.0
<=3.0.1" to ">=1.3.0 <3.0.0" while keeping "apiVersion": "v3" as-is; locate the
"apiVersion" and "generator" entries in the template and replace the generator
string with the new lower bound >=1.3.0 and exclusive upper bound <3.0.0.

Copy link
Member

Choose a reason for hiding this comment

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

actually update the value to >=2.0.0 <4.0.0, let us support latest AsyncAPI CLI v5

cc @Harsh16gupta

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@derberg done.
Updated the version range and reference repo. Please have a look.

Copy link
Member

Choose a reason for hiding this comment

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

but you pushed [__transpiled](https://github.com/Harsh16gupta/asyncapi-v3-template-final/tree/main/__transpiled) which is the result of generator transpilation. I meant you should push the result of generation. Look at https://69669ff3b5b23637cad28600--asyncapi-website.netlify.app/docs/tools/generator/generator-template#4-write-script-to-run-the-test-code and output. You need to make sure the new tutorial works end to end - and I need to be able to verify how you tested it

Copy link
Contributor Author

@Harsh16gupta Harsh16gupta Jan 14, 2026

Choose a reason for hiding this comment

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

I followed the same flow as the v2 docs and ran npm test, which internally does:

  • asyncapi generate fromTemplate test/fixtures/asyncapi.yml ./ --output test/project
  • then runs python test/project/test.py

The generated output for this tutorial is therefore test/project/client.py, and the runtime behavior is verified via test.py.

When I run this, I get exactly the same output as shown in the v2 tutorial logs (temperature dropped / risen messages), matching the expected behavior:
https://69669ff3b5b23637cad28600--asyncapi-website.netlify.app/docs/tools/generator/generator-template#5d-update-asyncapi-document:~:text=Run%20npm%20test%20to%20validate%20that%20everything,Where%20to%20go%20from%20here%3F

This confirms that the v2 → v3 conversion works end to end, and test/project is already committed in the repo so the generated output and verification steps are visible. I’ve also removed __transpiled since it’s not part of the generated output.

Please let me know if there’s any additional generated artifact you expect beyond test/project.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@derberg
I tried dong this
image
and I have commited the output generated to this
https://github.com/Harsh16gupta/Testing

Just wanted to confirm if this is what you were asking me to do

"supportedProtocols": ["mqtt"]
},
"dependencies": {
Expand Down Expand Up @@ -326,8 +330,8 @@ In **package.json** you can have the scripts property that you invoke by calling
"test": "npm run test:clean && npm run test:generate && npm run test:start"
},
"generator": {
"apiVersion": "v1",
"generator": ">=1.10.0 <2.0.0",
"apiVersion": "v3",
"generator": ">=1.10.0 <=3.0.1",
"supportedProtocols": ["mqtt"]
},
"dependencies": {
Expand Down Expand Up @@ -357,7 +361,7 @@ You often have different runtime environments in programming, e.g., development
```yml
servers:
dev:
url: test.mosquitto.org
host: test.mosquitto.org
protocol: mqtt
```

Expand Down Expand Up @@ -391,7 +395,7 @@ Update your `test:generate` script in **package.json** to include the server par
"test:generate": "asyncapi generate fromTemplate test/fixtures/asyncapi.yml ./ --output test/project --force-write --param server=dev"
```

You can now replace the static broker from `mqttBroker = 'test.mosquitto.org'` to `mqttBroker = "${asyncapi.servers().get(params.server).url()}"` in **index.js**.
You can now replace the static broker from `mqttBroker = 'test.mosquitto.org'` to `mqttBroker = "${asyncapi.servers().get(params.server).host()}"` in **index.js**.

Now the template code looks like this:

Expand All @@ -405,7 +409,7 @@ export default function ({ asyncapi, params }) {
<File name="client.py">
{`import paho.mqtt.client as mqtt

mqttBroker = "${asyncapi.servers().get(params.server).url()}"
mqttBroker = "${asyncapi.servers().get(params.server).host()}"

class TemperatureServiceClient:
def __init__(self):
Expand Down Expand Up @@ -436,7 +440,7 @@ export default function ({ asyncapi, params }) {
// 2
<Text newLines={2}>import paho.mqtt.client as mqtt</Text>
// 3
<Text newLines={2}>mqttBroker = "{asyncapi.servers().get(params.server).url()}"</Text>
<Text newLines={2}>mqttBroker = "{asyncapi.servers().get(params.server).host()}"</Text>
// 4
<Text newLines={2}>class {asyncapi.info().title().replaceAll(' ', '')}Client:</Text>
// 5
Expand Down Expand Up @@ -483,23 +487,23 @@ class TemperatureServiceClient:

```

You'll then need to template to dynamically generate `sendTemperatureDrop` and `sendTemperatureRise` functions in the generated code based off the AsyncAPI document content. The goal is to write template code that returns functions for channels that the Temperature Service application is subscribed to. The template code to generate these functions will look like this:
You'll then need a template to dynamically generate `sendTemperatureDrop` and `sendTemperatureRise` functions in the generated code based off the AsyncAPI document content. The goal is to write template code that returns functions for operations marked with `action: receive`, using their associated channels. The template code to generate these functions will look like this:

```js
<Text indent={2} newLines={2}>
<TopicFunction channels={asyncapi.channels().filterByReceive()} />
<TopicFunction operations={asyncapi.operations().filterByReceive()} />
</Text>
```

It's recommended to put reusable components outside the template directory in a new directory called components. You'll create a component that will dynamically generate functions in the output for as many channels as there are in your AsyncAPI document that contains a `publish` operation. Add the following code in the **python-mqtt-client-template/components/TopicFunction.js** file, after creating the **python-mqtt-client-template/components/** directory:
It's recommended to put reusable components outside the template directory in a new directory called components. You'll create a component that will dynamically generate functions in the output for as many operations as there are in your AsyncAPI document that are marked with `action: receive`. Add the following code in the **python-mqtt-client-template/components/TopicFunction.js** file, after creating the **python-mqtt-client-template/components/** directory:

```js
/*
* This component returns a block of functions that user can use to send messages to specific topic.
* As input it requires a list of Channel models from the parsed AsyncAPI document
* As input it requires a list of Operation models from the parsed AsyncAPI document marked with `action: receive`.
*/
export function TopicFunction({ channels }) {
const topicsDetails = getTopics(channels);
export function TopicFunction({ operations }) {
const topicsDetails = getTopics(operations);
let functions = '';

topicsDetails.forEach((t) => {
Expand All @@ -518,25 +522,28 @@ export function TopicFunction({ channels }) {
*
* As input it requires a list of Channel models from the parsed AsyncAPI document
*/
function getTopics(channels) {
const channelsCanSendTo = channels;
function getTopics(operations) {
let topicsDetails = [];

channelsCanSendTo.forEach((ch) => {
const topic = {};
const operationId = ch.operations().filterByReceive()[0].id();
topic.name = operationId.charAt(0).toUpperCase() + operationId.slice(1);
topic.topic = ch.address();

topicsDetails.push(topic);
})

operations.forEach((op) => {
const channels = op.channels().all();
if (!channels.length) return;

const channel = channels[0];
const operationId = op.operationId() || op.id();

topicsDetails.push({
name: operationId.charAt(0).toUpperCase() + operationId.slice(1),
topic: channel.address()
});
});

return topicsDetails;
}
```

`{ channels }`: the `TopicFunction` component accepts a custom prop called channels and in your template code
`getTopics(channels)`: Returns a list of objects, one for each channel with two properties; name and topic. The **name** holds information about the `operationId` provided in the AsyncAPI document while the **topic** holds information about the address of the topic.
`{ operations }`: the `TopicFunction` component accepts a custom prop called operations and in your template code
`getTopics(operations)`: Returns a list of objects, one for each operation with two properties; name and topic. The **name** holds information about the `operationId` provided in the AsyncAPI document (or a generated ID if operationId is not set) while the **topic** holds information about the address of the topic from the operation's associated channel.

Import the `TopicFunction` component in your template code in **index.js** and add the template code to generate the functions to topics that the `Temperature Service` application is subscribed to. In your case, the final version of your template code should look like this:

Expand All @@ -549,7 +556,7 @@ export default function ({ asyncapi, params }) {
<File name="client.py">
<Text newLines={2}>import paho.mqtt.client as mqtt</Text>

<Text newLines={2}>mqttBroker = "{asyncapi.servers().get(params.server).url()}"</Text>
<Text newLines={2}>mqttBroker = "{asyncapi.servers().get(params.server).host()}"</Text>

<Text newLines={2}>class {asyncapi.info().title().replaceAll(' ', '')}Client:</Text>

Expand All @@ -560,7 +567,7 @@ export default function ({ asyncapi, params }) {
</Text>

<Text indent={2} newLines={2}>
<TopicFunction channels={asyncapi.channels().filterByReceive()} />
<TopicFunction operations={asyncapi.operations().filterByReceive()} />
</Text>
</File>
)
Expand All @@ -587,39 +594,42 @@ python-mqtt-client-template

Run `npm test` on your terminal to ensure everything works as expected.

In the next section, you'll add another channel to **asyncapi.yml** file called `temperature/dropped` and `temperature/risen` then run the template again to make sure it still works as expected.
In the next section, you'll add another channel to **asyncapi.yml** file called `temperatureDropped` and `temperatureRisen` then run the template again to make sure it still works as expected.

#### 5d. Update AsyncAPI document

Update the AsyncAPI document to use two channels:

```yml
channels:
temperature/dropped:
description: Notifies the user when the temperature drops past a certain point.
publish:
operationId: temperatureDrop
message:
temperatureDropped:
address: temperature/dropped
messages:
temperatureDrop:
description: Message that is being sent when the temperature drops past a certain point.
payload:
type: object
additionalProperties: false
properties:
temperatureId:
type: string

temperature/risen:
description: Notifies the user when the temperature rises past a certain point.
publish:
operationId: temperatureRise
message:
$ref: '#/components/schemas/temperatureId'
description: Notifies the user when the temperature drops past a certain point.
temperatureRisen:
address: temperature/risen
messages:
temperatureRise:
description: Message that is being sent when the temperature rises past a certain point.
payload:
type: object
additionalProperties: false
properties:
temperatureId:
type: string
$ref: '#/components/schemas/temperatureId'
description: Notifies the user when the temperature rises past a certain point.

operations:
temperatureDrop:
action: receive
summary: Message sent to the broker when the temperature is dropped.
channel:
$ref: '#/channels/temperatureDropped'
temperatureRise:
action: receive
summary: Message sent to the broker when the temperature is risen.
channel:
$ref: '#/channels/temperatureRisen'
```

And update your test script in test.py to test the two functions as below:
Expand Down