From 542889e6a4af1f747ce10af4f3ebb7d3e10d4159 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Wed, 20 Jul 2022 11:26:33 +0300 Subject: [PATCH 01/26] add asyncapiDocument and asyncapiString documentation --- docs/asyncapi-file.md | 85 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/docs/asyncapi-file.md b/docs/asyncapi-file.md index d8c6dff45..b3f6ec625 100644 --- a/docs/asyncapi-file.md +++ b/docs/asyncapi-file.md @@ -3,4 +3,87 @@ title: "AsyncAPI Specification File" weight: 20 --- ->This document is under construction. \ No newline at end of file +### What is the Asyncapi Specification? +The **AsyncAPI specification** defines a standard, protocol-agnostic interface description of message-based or event-driven APIs which allows the people or machines communicating with one another to understand the capabilities of an event-driven API without requiring access to the source code, documentation or inspecting the network traffic. + +This specification file when fed as an input to the generator library using the **asyncAPI CLI command**, shown in the code snippet below, generates API documentation or API code with it. + +```bash +ag asyncapi.yaml ~/my-template +``` +1. **ag** is the asyncAPI generator +2. **asyncapi.yaml** is the specification file +3. **~/my-template** is the template you are using + +### Use cases of of the API definition file +- Interactive documentation +- Code generation +- Validation of messages the client receives +- Application of API management policies to messages before they arive to the broker + + + +If you are looking to learn how to create your own asyncapi specification file or you need to refresh your knowledge,check out our official [documentation](https://www.asyncapi.com/docs/reference/specification/v2.4.0) + + +In this documentation you'll learn about the inner working of the generator and what happens once the spec file is fed to the generator and how you can use the content of spec file using the asyncAPI document in your code. + + + +The generator receives the template and AsyncAPI specification file as an input. The illustration below clearly depicts the whole proccess from when you add the template and your specification file to the cli tool, to how the generator uses the input to generate the output you need. + +``` mermaid +graph LR + E[ Specification File ] -->| asyncapi specification | B(Generator) + F[ Generator Template ] -->| Template | B{Generator} + B -->| asyncapi String| C[Parser] + C -->|One| D[asyncapi Document] +``` +The generator library upon receiving as an input the specificication file and then generates code with it. As a user you will need access to the data that was defined in the specification file. +When you are writing your template, you get access to the specification file in two different forms; the originalAsyncApi which is a stringified version of the specification `.yml` file and the second is the asyncapiDocument + + +#### Method 1: asyncapiString + template ## +The **asynapiString** is a stringified version of your specification yaml that your template gets access to using the templates hook `createAsyncapiFile(generator)`. The template then gets the original specification file by calling `generator.originalAsyncAPI` which returns a stringified version of the original spec file. You can therefore use it in your generatoed application code. +Example: +``` +const asyncapiString = ` +asyncapi: 2.0.0 +info: + title: Example to show stringified specification file + version: 0.1.0 +channels: + example: + publish: + message: + schemaFormat: 'application/vnd.oai.openapi;version=3.0.0' + payload: # The following is an OpenAPI schema + type: object + properties: + title: + type: string + nullable: true + author: + type: string + example: Jack Johnson +` +``` + + + +#### Method 2: asyncapiDocument+ template ## +Once the specification yml or json is passed as an input to the generator library, it is passed on to the Parser library which then manipulates the file to a more structured document called the [asyncapiDocument](https://github.com/asyncapi/parser-js/blob/master/API.md#module_@asyncapi/parser+AsyncAPIDocument). It should be used to access the documents content for example, to extract the version of the spec file used for your Readme.md, you can do that using the asyncapiDocument by running `asyncapiDocument.version` or to get the message payload using `asyncapiDocument.allMessages` + + + +Note: How it simplifies the structure of the spec file which is complex and nested + +Note 2: Mention how you can check to see how these 2 docs are used in the written templates e.g node.js template +Note 3: https://github.com/asyncapi/template-for-generator-templates#template-context +Note 4: Both files are passed to the renderer engines ie React ans nunjucks +Note 5: You get access to these 2 files in the templates you will use +Note 6: Adv of one over the other +Note 7: Link to the parser docs or talk about the parser +Note 8: Show the structure of the asyncapiDocument as a code snippet +Note 9: Listen to the last section of the recording again \ No newline at end of file From 395db7468871788fe2d5126d35e9ffc64a3ceab3 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Tue, 15 Nov 2022 09:12:54 +0300 Subject: [PATCH 02/26] delete stale async-api file --- docs/asyncapi-file.md | 89 ------------------------------------------- 1 file changed, 89 deletions(-) delete mode 100644 docs/asyncapi-file.md diff --git a/docs/asyncapi-file.md b/docs/asyncapi-file.md deleted file mode 100644 index b3f6ec625..000000000 --- a/docs/asyncapi-file.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: "AsyncAPI Specification File" -weight: 20 ---- - -### What is the Asyncapi Specification? -The **AsyncAPI specification** defines a standard, protocol-agnostic interface description of message-based or event-driven APIs which allows the people or machines communicating with one another to understand the capabilities of an event-driven API without requiring access to the source code, documentation or inspecting the network traffic. - -This specification file when fed as an input to the generator library using the **asyncAPI CLI command**, shown in the code snippet below, generates API documentation or API code with it. - -```bash -ag asyncapi.yaml ~/my-template -``` -1. **ag** is the asyncAPI generator -2. **asyncapi.yaml** is the specification file -3. **~/my-template** is the template you are using - -### Use cases of of the API definition file -- Interactive documentation -- Code generation -- Validation of messages the client receives -- Application of API management policies to messages before they arive to the broker - - - -If you are looking to learn how to create your own asyncapi specification file or you need to refresh your knowledge,check out our official [documentation](https://www.asyncapi.com/docs/reference/specification/v2.4.0) - - -In this documentation you'll learn about the inner working of the generator and what happens once the spec file is fed to the generator and how you can use the content of spec file using the asyncAPI document in your code. - - - -The generator receives the template and AsyncAPI specification file as an input. The illustration below clearly depicts the whole proccess from when you add the template and your specification file to the cli tool, to how the generator uses the input to generate the output you need. - -``` mermaid -graph LR - E[ Specification File ] -->| asyncapi specification | B(Generator) - F[ Generator Template ] -->| Template | B{Generator} - B -->| asyncapi String| C[Parser] - C -->|One| D[asyncapi Document] -``` -The generator library upon receiving as an input the specificication file and then generates code with it. As a user you will need access to the data that was defined in the specification file. -When you are writing your template, you get access to the specification file in two different forms; the originalAsyncApi which is a stringified version of the specification `.yml` file and the second is the asyncapiDocument - - -#### Method 1: asyncapiString + template ## -The **asynapiString** is a stringified version of your specification yaml that your template gets access to using the templates hook `createAsyncapiFile(generator)`. The template then gets the original specification file by calling `generator.originalAsyncAPI` which returns a stringified version of the original spec file. You can therefore use it in your generatoed application code. -Example: -``` -const asyncapiString = ` -asyncapi: 2.0.0 -info: - title: Example to show stringified specification file - version: 0.1.0 -channels: - example: - publish: - message: - schemaFormat: 'application/vnd.oai.openapi;version=3.0.0' - payload: # The following is an OpenAPI schema - type: object - properties: - title: - type: string - nullable: true - author: - type: string - example: Jack Johnson -` -``` - - - -#### Method 2: asyncapiDocument+ template ## -Once the specification yml or json is passed as an input to the generator library, it is passed on to the Parser library which then manipulates the file to a more structured document called the [asyncapiDocument](https://github.com/asyncapi/parser-js/blob/master/API.md#module_@asyncapi/parser+AsyncAPIDocument). It should be used to access the documents content for example, to extract the version of the spec file used for your Readme.md, you can do that using the asyncapiDocument by running `asyncapiDocument.version` or to get the message payload using `asyncapiDocument.allMessages` - - - -Note: How it simplifies the structure of the spec file which is complex and nested - -Note 2: Mention how you can check to see how these 2 docs are used in the written templates e.g node.js template -Note 3: https://github.com/asyncapi/template-for-generator-templates#template-context -Note 4: Both files are passed to the renderer engines ie React ans nunjucks -Note 5: You get access to these 2 files in the templates you will use -Note 6: Adv of one over the other -Note 7: Link to the parser docs or talk about the parser -Note 8: Show the structure of the asyncapiDocument as a code snippet -Note 9: Listen to the last section of the recording again \ No newline at end of file From 359ad9cdc7de19127819a2882b31224354e57031 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Thu, 1 Jun 2023 07:05:33 +0300 Subject: [PATCH 03/26] first draft of the generator tutorial --- docs/generator_template.md | 591 +++++++++++++++++++++++++++++++++++++ 1 file changed, 591 insertions(+) create mode 100644 docs/generator_template.md diff --git a/docs/generator_template.md b/docs/generator_template.md new file mode 100644 index 000000000..054deb82c --- /dev/null +++ b/docs/generator_template.md @@ -0,0 +1,591 @@ +--- +title: "How to create a simple generator template" +weight: 170 +--- + +In this tutorial, you'll learn to create a simple generator template using a python MQTT client. We will use the AsyncAPI document and the template we develop to generate code. + +## Background context + +There is a list of [community maintained templates](https://www.asyncapi.com/docs/tools/generator/template#generator-templates-list) but sometimes, your needs might not be met by the available templates requiring you to write custom templates. You will use MQTT protocol to send messages between IOT devices. To generate code, you will use the [asyncapi cli](https://www.asyncapi.com/tools/cli) If you don;t have the CLI inttsalled follow [this guide](https://www.asyncapi.com/docs/tools/generator/installation-guide#asyncapi-cli). Before you create the template, you'll need to have an [asyncapi document](https://www.asyncapi.com/docs/tools/generator/asyncapi-document) to test the template against. + +## Prerequisite + +In this tutorial, you'll use the following template saved in `asyncapi.yml` file in your template project directory. + +``` yml + +asyncapi: 2.6.0 + +info: + title: Temperature Service + version: 1.0.0 + description: This service is in charge of processing all the events related to temperature. + +servers: + dev: + url: test.mosquitto.org + protocol: mqtt + bindings: + mqtt: + clientId: temperature-service + +channels: + temperature/changed: + description: Updates the bedroom temperature in the database when the temperatures drops or goes up. + publish: + operationId: temperatureChange + message: + description: Message that is being sent when the temperature in the bedroom changes. + payload: + $ref: '#/components/schemas/temperatureId' +components: + schemas: + temperatureId: + type: object + additionalProperties: false + properties: + temperatureId: + type: string +``` + +In this tutorial: + +- You'll use the [Eclipse Mosquito](https://test.mosquitto.org) **MQTT broker** which you'll connect to 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. +- Lastly, you will create a template that will use MQTT to allow use to monitor your home system camera and notify us when there's someone at the door by creating sub/pub channels. + +> Learn more about asyncronous messaging using MQTT [here]() + +## Steps followed to create a template / Template structure + +1. Install the AsyncAPI CLI using the command `npm install -g @asyncapi/cli`. +2. Create a new directory for your template named **python-mqtt-client-template**. +3. Create a new folder **template** with a file named `template.yml` in your template directory. This file is used to define the **structure** of your template. +4. Create a new file named `package.json` in your template directory. This file is used to define the **dependencies** for your template. +5. Create a new file named `index.js` in your template directory. This file is used to define the **logic** for your template. +6. Create a new directory named `partials` in your template directory. This directory is used to store the **partial HTML** files that are used to create the final documentation. +7. Create a new directory named `assets` in your template directory. This directory is used to **store the CSS and JavaScript files that are used to style the final documentation or website**. + +Lets break it down: + +### `package.json` file + +The package.json file is used to define the dependencies for your template. Here's an example package.json file: + +``` json +{ + "name": "python-mqtt-client-template", + "version": "0.0.1", + "description": "A template that generates a Python MQTT client using MQTT.", + "generator": { + "renderer": "react", + "apiVersion": "v1", + "generator": ">=1.10.0 <2.0.0", + "supportedProtocols": ["mqtt"] + }, + "dependencies": { + "@asyncapi/generator-react-sdk": "^0.2.25" + } +} +``` + +Here's what is contained in the code snippet above: + +- **name** -the name of your template +- **version** - the current version of your template +- **description** - a description of what your template does +- **generator** - specify generator [specific configuration](https://www.asyncapi.com/docs/tools/generator/configuration-file) + - **renderer** - can either be `react` or `nunjucks`. In this case the generator will pass your template to the react render engine so it can generate the output. + - **apiVersion** - specifies which major version of the [Parser-API](https://github.com/asyncapi/parser-api) your template will use. + - **generator** - a string representing the generator version-range your template is compatible with. + - **supportedProtocols** - A list that specifies which protocols are supported by your template. +- **dependencies** - specifies which version of [`@asyncapi/generator-react-sdk`](https://github.com/asyncapi/generator-react-sdk) should be used. + +Run the command `npm install` on your terminal to install the dependencies specified in `package.json`. + +### `index.js` file + +The index.js file is used to define the logic for your template. Inside the template folder, create an `index.js` file and add the code snippet below: + +```js +//1 +import { File } from '@asyncapi/generator-react-sdk' +//2 +export default function ({ asyncapi }) { + //3 + return {asyncapi.info().title()} +} +``` + +The code snippet above does the following: + +1. Import the `generator-react-sdk` dependency. +2. The `asyncapi` argument is an instance of the [AsyncAPI Parser](https://www.asyncapi.com/docs/tools/generator/parser). It will allow you to access the content of the asyncapi document in your template using helper functions. +3. The `asyncapi.info().title()` is using the info() helper function to return the info object from the AsyncAPI document illustrated in the code snippet below: + +``` json +info: + title: Temperature Service + version: 1.0.0 + description: This service is in charge of processing all the events related to temperature. +``` + +`asyncapi.info().title()` will return Temperature Service. + +### Use AsyncAPI CLI to test the template + +To see this in action, run `asyncapi generate fromTemplate asyncapi.yml ./ -o output` command on your terminal. If successful, you'll see the message below on your terminal: + +``` cmd +Generation in progress. Keep calm and wait a bit... done +Check out your shiny new generated files at output. +``` + +And navigating to the **output** directory, you should see a **client.py** file and the only content is Temperature Service. + +Let's break down the previous command: + +- `asyncapi generate fromTemplate` is how you use AsyncAPI generator via the AsyncAPI CLI. +- `asyncapi.yaml` points to your AsyncAPI document. +- `./` specifies the location of your template. +- `-o` determines where to output the result. + + +-------- + + +``` js + +const generator = require('@asyncapi/generator'); +const pahoTemplate = require('@asyncapi/python-paho-template'); + +generator.registerTemplate('python-paho', pahoTemplate); + +const templateName = 'python-paho'; + +const options = { + templateParams: { + mqttBroker: 'test.mosquitto.org', + mqttClientId: 'my-client-id' + }, + target: resolve(__dirname, 'output'), + template: templateName, + overwrite: true +}; + +const specFile = resolve(__dirname, 'asyncapi.yml'); + +generator.generateFromFile(specFile, options) + .then(() => console.log('Generation complete!')) + .catch(console.error); +``` + +## Creating a template + +We will create an MQTT supported template that will generate a python client from the template and the asyncAPI document above. + +### Create the client + +In this section, you'll: + +1. Write the MQTT client code. +2. Write code to test the client works +3. Update the template to use the client code. +4. Setup a script to help you run this code +5. Template your code. + +The following code is an example of a Python client using the paho-MQTT library: + +``` python +# 1 +import paho.mqtt.client as mqtt +# 2 +mqttBroker = "test.mosquitto.org" + +class TemperatureServiceClient: + def __init__(self): + # 3 + self.client = mqtt.Client() + # 4 + self.client.connect(mqttBroker) + + + def sendTemperatureChange(self, id): + # 5 + topic = "temperature/changed" + # 6 + self.client.publish(topic, id) +``` + +Make sure you have the paho-mqtt library installed. You can install it using pip with the `pip install paho-mqtt` command. +Let's break down the previous code snippet: + +1. Imports the mqtt module from the paho package, which provides the MQTT client functionality. +2. Assigns the MQTT broker address `test.mosquitto.org` to the variable mqttBroker. This specifies the location where the MQTT client will connect to. +3. Creates an instance of the MQTT client object. This object will be used to establish a connection with the MQTT broker and perform MQTT operations. +4. Establishes a connection to the MQTT broker. This command connects the MQTT client to the broker. +5. The MQTT topic to which the client will publish messages. +6. This command publishes the temperature change information to the MQTT broker. + +In summary, this code sets up an MQTT client using the paho-MQTT library. It connects to the test.mosquitto.org MQTT broker, and the sendTemperatureChange() method publishes temperature change information to the **temperature/changed** topic whenever called. + +### Test the client + +You'll interact with the Temperature Service using the client module you created above. You;ll create an instance of the client using client = TemperatureServiceClient() and then use client.sendTemperatureChange function to publish messages that Temperature Service is subscribed to. +Create a **test.py** file in your project and add the code snippet below: + +``` python +from client import TemperatureServiceClient +from random import randrange +import time + +client = TemperatureServiceClient() + +id_length = 8 +min_value = 10**(id_length-1) # Minimum value with 8 digits (e.g., 10000000) +max_value = 10**id_length - 1 # Maximum value with 8 digits (e.g., 99999999) + +while True: + randomId = randrange(min_value, max_value + 1) + client.sendTemperatureChange(randomId) + print("New temperature detected " + str(randomId) + " sent to temperature/changed") + time.sleep(1) + +``` + +Run the code above on your terminal using the command `python test.py`. You'll should see output similar to the snippet below logged on your terminal: + +``` cmd +New temperature detected 64250266 sent to temperature/changed +New temperature detected 36947728 sent to temperature/changed +New temperature detected 72955029 sent to temperature/changed +``` + +To make sure your client works, also test it using an [MQTT CLI](https://hivemq.github.io/mqtt-cli/) using docker. Run the command `docker run hivemq/mqtt-cli sub -t comment/liked -h test.mosquitto.org` on your teminal. It will download the image if you don't have it locally then the CLI will conncet to the broker, subscribe to the `temperature/changed` topic and then output the temperature ids on the terminal. + +### Update the template with client code + +Open **index.js** and copy the content of **client.py** and replace `{asyncapi.info().title()}` with it. It should look like the code snippet below now: + +``` js +import { File } from '@asyncapi/generator-react-sdk'; + +export default function ({ asyncapi }) { + return ( + + {`import paho.mqtt.client as mqtt + +mqttBroker = "test.mosquitto.org" + +class TemperatureServiceClient: + def __init__(self): + self.client = mqtt.Client() + self.client.connect(mqttBroker) + + + def sendTemperatureChange(self, id): + topic = "temperature/changed" + self.client.publish(topic, id)`} + + ) +} +``` + +### Write script to run the test code + +In **package.json** you can have the scripts property that you can invoke by calling `npm run `. Add these scripts to **package.json**: + +``` json + "scripts": { + "test:clean": "rimraf test/project/client.py", + "test:generate": "asyncapi generate fromTemplate test/fixtures/asyncapi.yml ./ --output test/project --force-write", + "test:start": "python test/project/test.py", + "test": "npm run test:clean && npm run test:generate && npm run test:start" + } +``` + +The 4 scripts above do the following: + +1. `test:clean`: This script uses the rimraf package to remove the old version of the file **test/project/client.py** everytime you run your test. +2. `test:generate`: This script uses the AsyncAPI CLI to generate a new version of **client.py** +3. `test:start`: This script runs the python code using **client.py** +4. `test`: This script runs `npm test` to check that everything is working as expected. + +Run `npm test` on your terminal to ensure everything works as expected. + +## Template your code + +### Add parameters to the configuration file + +In programming we often have different runtime environments e.g development and production. You will use different servers to spin both of these instances. In your case, you'll probably have two broker versions one for use in production and the other in development. You have defined a dev server in the AsyncAPI document: + +```yml +servers: + dev: + url: test.mosquitto.org + protocol: mqtt + bindings: + mqtt: + clientId: temperature-service +``` + +You can also define the broker you will use in production in the servers section. +Therefore, we can template the code `mqttBroker = 'test.mosquitto.org'` in **index.js** so the value is populated dynamically at runtime depending on the specified server environment. + +Generator has a **parameters** object used to define parameters you use to dynamically to modify your template code at runtime. It also supports the **server** parameter that defines the server configuration value. Navigate to **package.json** and add the snippet below: + +```json + "generator": { + # ...(redacted for brevity) + "parameters": { + "server": { + "description": "The server you want to use in the code.", + "required": true + } + } + } +``` + +`"required": true`: makes the parameter mandatory and once user forgets to add it to the cli command, a proper error message is yielded. +You'll pass the server to be used to generate your code using `--param server=dev` in the AsyncAPI CLI command. Failure to which you'll get an error: + +```cmd +Generator Error: This template requires the following missing params: server. +``` + +Update your `test:generate` script in package.json to inlcude the server param `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**. + +Now the template code looks like: + +``` js +import { File } from '@asyncapi/generator-react-sdk'; + +// notice that now the template not only gets the instance of parsed AsyncAPI document but also the parameters +export default function ({ asyncapi }) { + console.log(asyncapi, params) + return ( + + {`import paho.mqtt.client as mqtt + +mqttBroker = "${asyncapi.servers().get(params.server).url()}" + +class TemperatureServiceClient: + def __init__(self): + self.client = mqtt.Client() + self.client.connect(mqttBroker) + + + def sendTemperatureChange(self, id): + topic = "temperature/changed" + self.client.publish(topic, id)`} + + ) +} +``` + +Run `npm test` to validate that your code still works as expected. + +### Templating index.js with React + +```js +// 1 +import { File, Text } from '@asyncapi/generator-react-sdk' +export default function ({ asyncapi, params }) { + return ( + + // 2 + import paho.mqtt.client as mqtt + // 3 + mqttBroker = "{asyncapi.servers().get(params.server).url()}" + // 4 + class {asyncapi.info().title().replaceAll(' ', '')}Client: + // 5 + + {`def __init__(self): + self.client = mqtt.Client() + self.client.connect(mqttBroker)`} + + ) +} +``` + +1. Import the **Text** component that will wrap strings so they are indented properly in the output which is required in Python. Your import statement should now look like this: `import { File, Text } from '@asyncapi/generator-react-sdk'`. +2. When the paho module import is rendered in **client.py** file, it will add two extra new lines. +3. The broker url is templated in a Text component removing the `$` from the string template. +4. Pick the class name **TemperatureServiceClient** from the AsyncAPI document from the **info** object using the Parser API using the code: `asyncapi.info().title()` which will return `Temperature Service`. It will remove the spaces and add Client as a suffix. +5. There is no templating needed in the `__init__` function, there is only hardcoded information. + +> If you're on the fence about which templating engine you should use in your template, check out the [react render engine](https://www.asyncapi.com/docs/tools/generator/react-render-engine) and [nunjucks render engine](https://www.asyncapi.com/docs/tools/generator/nunjucks-render-engine) documentation. +In this section, you'll refactor your template to use React. + +### Creating a reusable component + +If you had another two [channels](https://www.asyncapi.com/docs/concepts/channel), one to watch if the temperature drop below a set value and one to check if the temperature is above a set value, the generated output code would look like this: + +```python +import paho.mqtt.client as mqtt + +mqttBroker = "test.mosquitto.org" + +class TemperatureServiceClient: + + def __init__(self): + self.client = mqtt.Client() + self.client.connect(mqttBroker) + + def sendTemperatureDropped(self, id): + topic = "temperature/droped" + self.client.publish(topic, id) + def sendTemperatureRisen(self, id): + topic = "temperature/risen" + self.client.publish(topic, id) + +``` + +You'll then need to template to dynamically generate `sendTemperatureDropped` and `sendTemperatureRisen` 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 will look like this: + +```js + + + +``` + +It's recommended to put reusable components outside template directory in a new directory called **components**. In the next section, 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 contain a `publish` operation. Add the following code in **components/TopicFunctions.js** file: + +```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 + */ +export function TopicFunction({ channels }) { + const topicsDetails = getTopics(channels) + let functions = '' + + topicsDetails.forEach((t) => { + functions += `def send${t.name}(self, id): + topic = "${t.topic}" + self.client.publish(topic, id)\n` + }) + + return functions +} + +/* + * This function returns a list of objects, one for each channel with two properties, name and topic + * name - holds information about the operationId provided in the AsyncAPI document + * topic - holds information about the address of the topic + * + * As input it requires a list of Channel models from the parsed AsyncAPI document + */ +function getTopics(channels) { + const channelsCanSendTo = channels + 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) + }) + + return topicsDetails +} +``` + +`{ channels }`:the TopicFunction component accepts a custom prop called channels and in your template code, you can call the comment as shown in the snippet below: +`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. +> Link to where they can read more about it +> +Import the component in your template code in **index.js**. The final version of your template code should look like this: + +```js +import { File, Text } from '@asyncapi/generator-react-sdk' +import { TopicFunction } from '../components/TopicFunction' + +export default function ({ asyncapi, params }) { + return ( + + import paho.mqtt.client as mqtt + + mqttBroker = "{asyncapi.servers().get(params.server).url()}" + + class {asyncapi.info().title().replaceAll(' ', '')}Client: + + + {`def __init__(self): + self.client = mqtt.Client() + self.client.connect(mqttBroker)`} + + + + + + + ) +} + +``` + +Run `npm test` on your terminal to ensure everything works as expected. +Add another channel to asyncapi.yml file called `temperatureDropped` and `temperatureRisen` then run the template again to make sure it still works as expected. + +You'll have the TopicFunction component tha's reusable in other scenarios to return topic-dedicated functions. In your case, you'll get access to topics that the Temperature Service application is subscribed to. + +#### Update AsyncAPi docs + +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: + 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: + description: Message that is being sent when the temperature rises past a certain point. + payload: + type: object + additionalProperties: false + properties: + temperatureId: + type: string +``` + +And update your test script in test.py to test the two functions as below: + +```py + client.sendTemperatureDrop(randomId) + print("Temperature drop detected " + str(randomId) + " sent to temperature/dropped") + client.sendTemperatureRise(randomId) + print("Temperature rise detected " + str(randomId) + " sent to temperature/risen") +``` + +Run `npm test` to validate that everything works as expected. You should see logs similar to the snippet below in your terminal: + +```cmd +Temperature drop detected 49040460 sent to temperature/dropped +Temperature rise detected 49040460 sent to temperature/risen +Temperature drop detected 66943992 sent to temperature/dropped +Temperature rise detected 66943992 sent to temperature/risen +``` + +## Conclusion + +In this tutorial, we have created a simple AsyncAPI generator template that uses a Python MQTT client. We have explained how to use an AsyncAPI file, create an python MQTT template and use them to generate code from it and use the Paho-MQTT library in Python to connect to an MQTT broker and publish messages. We hope this tutorial has helped you understand how to create the template. From d2d1684e865d8f6e6acd7be8993740c0a42fd7dc Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Mon, 5 Jun 2023 13:51:20 +0300 Subject: [PATCH 04/26] first editorial review --- docs/generator_template.md | 145 ++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 84 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index 054deb82c..af7ac5800 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -3,15 +3,21 @@ title: "How to create a simple generator template" weight: 170 --- -In this tutorial, you'll learn to create a simple generator template using a python MQTT client. We will use the AsyncAPI document and the template we develop to generate code. +In this tutorial, you'll learn to create a simple generator template using a python MQTT client. You'll use the AsyncAPI document and the template you develop to generate python code. Additionally, you'll create template code with a reusable component to reuse the custom functionality you create and test your code using an MQTT client. -## Background context +Let's suppose that you can only sleep when the AC in your bedroon is set to 22 °C and any you can't when the temperature drops or rises above that. You can install a smart monitor in your bedroom that keeps track of the temperature and notifies you to adjust your bedroom to your optimum temperature if it flactuates. You will create a template that sends alerts to notify you when the temperature fluctates from 22 °C. -There is a list of [community maintained templates](https://www.asyncapi.com/docs/tools/generator/template#generator-templates-list) but sometimes, your needs might not be met by the available templates requiring you to write custom templates. You will use MQTT protocol to send messages between IOT devices. To generate code, you will use the [asyncapi cli](https://www.asyncapi.com/tools/cli) If you don;t have the CLI inttsalled follow [this guide](https://www.asyncapi.com/docs/tools/generator/installation-guide#asyncapi-cli). Before you create the template, you'll need to have an [asyncapi document](https://www.asyncapi.com/docs/tools/generator/asyncapi-document) to test the template against. +In this tutorial: -## Prerequisite +- You'll use the [Eclipse Mosquito](https://test.mosquitto.org) **MQTT broker** which you'll connect to 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. +- Lastly, you will 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. +- Create a reusable component to create the rise/dropped temperature functions in the output code. -In this tutorial, you'll use the following template saved in `asyncapi.yml` file in your template project directory. +## Background context + +There is a list of [community maintained templates](https://www.asyncapi.com/docs/tools/generator/template#generator-templates-list) but what if you require customized output from the generator? In that case, you'll create a user-defined template that generates custom output from the generator. +Before you create the template, you'll need to have an [asyncapi document](https://www.asyncapi.com/docs/tools/generator/asyncapi-document),that defines the properties you want to use in your template, to test the template against. In this tutorial, you'll use the following template saved in `test/fixtures/asyncapi.yml` file in your template project directory. ``` yml @@ -38,7 +44,11 @@ channels: message: description: Message that is being sent when the temperature in the bedroom changes. payload: - $ref: '#/components/schemas/temperatureId' + type: object + additionalProperties: false + properties: + temperatureId: + type: string components: schemas: temperatureId: @@ -49,21 +59,19 @@ components: type: string ``` -In this tutorial: - -- You'll use the [Eclipse Mosquito](https://test.mosquitto.org) **MQTT broker** which you'll connect to 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. -- Lastly, you will create a template that will use MQTT to allow use to monitor your home system camera and notify us when there's someone at the door by creating sub/pub channels. +Note: -> Learn more about asyncronous messaging using MQTT [here]() +- To generate code, you will use the [asyncapi cli](https://www.asyncapi.com/tools/cli). If you don't have the CLI installed follow [this guide](https://www.asyncapi.com/docs/tools/generator/installation-guide#asyncapi-cli). +- If you are new to asyncapi, checkout the following docs: [template development](https://www.asyncapi.com/docs/tools/generator/template-development) which explains the minimum requirements for a template and possible features. +- Learn more about asyncronous messaging using MQTT [here](https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4). -## Steps followed to create a template / Template structure +## Steps followed to create a template -1. Install the AsyncAPI CLI using the command `npm install -g @asyncapi/cli`. -2. Create a new directory for your template named **python-mqtt-client-template**. -3. Create a new folder **template** with a file named `template.yml` in your template directory. This file is used to define the **structure** of your template. +1. Create a new directory for your template named **python-mqtt-client-template**. +2. Install the AsyncAPI CLI using the command `npm install -g @asyncapi/cli`. +3. Create a new folder **test/fixtures** with a file named `asyncapi.yml` in your fixtures directory. This file is used to define the **structure** of your template. 4. Create a new file named `package.json` in your template directory. This file is used to define the **dependencies** for your template. -5. Create a new file named `index.js` in your template directory. This file is used to define the **logic** for your template. +5. Create a new file named `index.js` in your **template** directory. This file is used to define the **logic** for your template. 6. Create a new directory named `partials` in your template directory. This directory is used to store the **partial HTML** files that are used to create the final documentation. 7. Create a new directory named `assets` in your template directory. This directory is used to **store the CSS and JavaScript files that are used to style the final documentation or website**. @@ -71,7 +79,7 @@ Lets break it down: ### `package.json` file -The package.json file is used to define the dependencies for your template. Here's an example package.json file: +The `package.json` file is used to define the dependencies for your template. Here's an example `package.json` file: ``` json { @@ -92,11 +100,11 @@ The package.json file is used to define the dependencies for your template. Here Here's what is contained in the code snippet above: -- **name** -the name of your template -- **version** - the current version of your template -- **description** - a description of what your template does -- **generator** - specify generator [specific configuration](https://www.asyncapi.com/docs/tools/generator/configuration-file) - - **renderer** - can either be `react` or `nunjucks`. In this case the generator will pass your template to the react render engine so it can generate the output. +- **name** -the name of your template. +- **version** - the current version of your template. +- **description** - a description of what your template does. +- **generator** - specify generator [specific configuration](https://www.asyncapi.com/docs/tools/generator/configuration-file). + - **renderer** - can either be `react` or `nunjucks`. In this case the generator will pass your template to the react render engine to generate the output. - **apiVersion** - specifies which major version of the [Parser-API](https://github.com/asyncapi/parser-api) your template will use. - **generator** - a string representing the generator version-range your template is compatible with. - **supportedProtocols** - A list that specifies which protocols are supported by your template. @@ -133,16 +141,16 @@ info: `asyncapi.info().title()` will return Temperature Service. -### Use AsyncAPI CLI to test the template +### Test using AsyncAPI CLI -To see this in action, run `asyncapi generate fromTemplate asyncapi.yml ./ -o output` command on your terminal. If successful, you'll see the message below on your terminal: +To see this in action, run `asyncapi generate fromTemplate test/fixtures/asyncapi.yml ./ -o test/project` command on your terminal. If successful, you'll see the message below on your terminal: ``` cmd Generation in progress. Keep calm and wait a bit... done Check out your shiny new generated files at output. ``` -And navigating to the **output** directory, you should see a **client.py** file and the only content is Temperature Service. +And navigating to the **project** directory, you should see a **client.py** file and the only content is Temperature Service. Let's break down the previous command: @@ -151,42 +159,10 @@ Let's break down the previous command: - `./` specifies the location of your template. - `-o` determines where to output the result. - --------- - - -``` js - -const generator = require('@asyncapi/generator'); -const pahoTemplate = require('@asyncapi/python-paho-template'); - -generator.registerTemplate('python-paho', pahoTemplate); - -const templateName = 'python-paho'; - -const options = { - templateParams: { - mqttBroker: 'test.mosquitto.org', - mqttClientId: 'my-client-id' - }, - target: resolve(__dirname, 'output'), - template: templateName, - overwrite: true -}; - -const specFile = resolve(__dirname, 'asyncapi.yml'); - -generator.generateFromFile(specFile, options) - .then(() => console.log('Generation complete!')) - .catch(console.error); -``` - ## Creating a template We will create an MQTT supported template that will generate a python client from the template and the asyncAPI document above. -### Create the client - In this section, you'll: 1. Write the MQTT client code. @@ -195,6 +171,8 @@ In this section, you'll: 4. Setup a script to help you run this code 5. Template your code. +## 1. Create the client + The following code is an example of a Python client using the paho-MQTT library: ``` python @@ -228,12 +206,12 @@ Let's break down the previous code snippet: 5. The MQTT topic to which the client will publish messages. 6. This command publishes the temperature change information to the MQTT broker. -In summary, this code sets up an MQTT client using the paho-MQTT library. It connects to the test.mosquitto.org MQTT broker, and the sendTemperatureChange() method publishes temperature change information to the **temperature/changed** topic whenever called. +In summary, this code sets up an MQTT client using the paho-MQTT library. It connects to the `test.mosquitto.or`g MQTT broker, and the `sendTemperatureChange()` method publishes temperature change information to the `temperature/changed` topic whenever called. -### Test the client +### 2.Test the client -You'll interact with the Temperature Service using the client module you created above. You;ll create an instance of the client using client = TemperatureServiceClient() and then use client.sendTemperatureChange function to publish messages that Temperature Service is subscribed to. -Create a **test.py** file in your project and add the code snippet below: +You'll interact with the Temperature Service using the client module you created above. You'll create an instance of the client using `client = TemperatureServiceClient()` and then use `client.sendTemperatureChange` function to publish messages that Temperature Service is subscribed to. +Create a **test/project/test.py** file in your project and add the code snippet below: ``` python from client import TemperatureServiceClient @@ -264,7 +242,7 @@ New temperature detected 72955029 sent to temperature/changed To make sure your client works, also test it using an [MQTT CLI](https://hivemq.github.io/mqtt-cli/) using docker. Run the command `docker run hivemq/mqtt-cli sub -t comment/liked -h test.mosquitto.org` on your teminal. It will download the image if you don't have it locally then the CLI will conncet to the broker, subscribe to the `temperature/changed` topic and then output the temperature ids on the terminal. -### Update the template with client code +### 3.Update the template with client code Open **index.js** and copy the content of **client.py** and replace `{asyncapi.info().title()}` with it. It should look like the code snippet below now: @@ -292,9 +270,9 @@ class TemperatureServiceClient: } ``` -### Write script to run the test code +### 4. Write script to run the test code -In **package.json** you can have the scripts property that you can invoke by calling `npm run `. Add these scripts to **package.json**: +In **package.json** you can have the scripts property that you invoke by calling `npm run `. Add these scripts to **package.json**: ``` json "scripts": { @@ -314,7 +292,7 @@ The 4 scripts above do the following: Run `npm test` on your terminal to ensure everything works as expected. -## Template your code +### 5. Template your code ### Add parameters to the configuration file @@ -330,7 +308,7 @@ servers: clientId: temperature-service ``` -You can also define the broker you will use in production in the servers section. +This will allow you to also define the broker you will use in production in the servers section above. Therefore, we can template the code `mqttBroker = 'test.mosquitto.org'` in **index.js** so the value is populated dynamically at runtime depending on the specified server environment. Generator has a **parameters** object used to define parameters you use to dynamically to modify your template code at runtime. It also supports the **server** parameter that defines the server configuration value. Navigate to **package.json** and add the snippet below: @@ -354,7 +332,7 @@ You'll pass the server to be used to generate your code using `--param server=de Generator Error: This template requires the following missing params: server. ``` -Update your `test:generate` script in package.json to inlcude the server param `test:generate": "asyncapi generate fromTemplate test/fixtures/asyncapi.yml ./ --output test/project --force-write --param server=dev "` +Update your `test:generate` script in `package.json` to inlcude the server param `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**. Now the template code looks like: @@ -389,6 +367,8 @@ Run `npm test` to validate that your code still works as expected. ### Templating index.js with React +Python takes indentation very seriously and out generated output will be python code. We therefpre need to make sure the indentation in index.js looks right so the generated code is indented properly. After templating the code in index.js, it will look like the following code snippet: + ```js // 1 import { File, Text } from '@asyncapi/generator-react-sdk' @@ -411,18 +391,18 @@ export default function ({ asyncapi, params }) { } ``` -1. Import the **Text** component that will wrap strings so they are indented properly in the output which is required in Python. Your import statement should now look like this: `import { File, Text } from '@asyncapi/generator-react-sdk'`. +1. Import the **Text** component that will wrap strings so they are indented properly in the output. Your import statement should now look like this: `import { File, Text } from '@asyncapi/generator-react-sdk'`. 2. When the paho module import is rendered in **client.py** file, it will add two extra new lines. 3. The broker url is templated in a Text component removing the `$` from the string template. -4. Pick the class name **TemperatureServiceClient** from the AsyncAPI document from the **info** object using the Parser API using the code: `asyncapi.info().title()` which will return `Temperature Service`. It will remove the spaces and add Client as a suffix. +4. Dynamically get the class name **TemperatureServiceClient** from the AsyncAPI document from the **info** object using the Parser API using the code: `asyncapi.info().title()` . It will return `Temperature Service`, then remove the spaces and add Client as a suffix. 5. There is no templating needed in the `__init__` function, there is only hardcoded information. > If you're on the fence about which templating engine you should use in your template, check out the [react render engine](https://www.asyncapi.com/docs/tools/generator/react-render-engine) and [nunjucks render engine](https://www.asyncapi.com/docs/tools/generator/nunjucks-render-engine) documentation. -In this section, you'll refactor your template to use React. +In the next section, you'll refactor your template to use React. ### Creating a reusable component -If you had another two [channels](https://www.asyncapi.com/docs/concepts/channel), one to watch if the temperature drop below a set value and one to check if the temperature is above a set value, the generated output code would look like this: +If you had two [channels](https://www.asyncapi.com/docs/concepts/channel), one to watch if the temperature drop below 22 °C and one to check if the temperature is above 22 °C, the generated output code would look like this: ```python import paho.mqtt.client as mqtt @@ -435,16 +415,16 @@ class TemperatureServiceClient: self.client = mqtt.Client() self.client.connect(mqttBroker) - def sendTemperatureDropped(self, id): + def sendTemperatureDrop(self, id): topic = "temperature/droped" self.client.publish(topic, id) - def sendTemperatureRisen(self, id): + def sendTemperatureRise(self, id): topic = "temperature/risen" self.client.publish(topic, id) ``` -You'll then need to template to dynamically generate `sendTemperatureDropped` and `sendTemperatureRisen` 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 will look like this: +You'll then need to template to dynamically generate `sendTemperatureDropped` and `sendTemperatureRisen` 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: ```js @@ -452,7 +432,7 @@ You'll then need to template to dynamically generate `sendTemperatureDropped` an ``` -It's recommended to put reusable components outside template directory in a new directory called **components**. In the next section, 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 contain a `publish` operation. Add the following code in **components/TopicFunctions.js** file: +It's recommended to put reusable components outside 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 contain a `publish` operation. Add the following code in **components/TopicFunctions.js** file: ```js /* @@ -497,10 +477,9 @@ function getTopics(channels) { ``` `{ channels }`:the TopicFunction component accepts a custom prop called channels and in your template code, you can call the comment as shown in the snippet below: -`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. -> Link to where they can read more about it -> -Import the component in your template code in **index.js**. The final version of your template code should look like this: +`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. + +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: ```js import { File, Text } from '@asyncapi/generator-react-sdk' @@ -530,12 +509,10 @@ export default function ({ asyncapi, params }) { ``` -Run `npm test` on your terminal to ensure everything works as expected. +Run `npm test` on your terminal to ensure everything works as expected. Add another channel to asyncapi.yml file called `temperatureDropped` and `temperatureRisen` then run the template again to make sure it still works as expected. -You'll have the TopicFunction component tha's reusable in other scenarios to return topic-dedicated functions. In your case, you'll get access to topics that the Temperature Service application is subscribed to. - -#### Update AsyncAPi docs +#### Update AsyncAPi document Update the AsyncAPI document to use two channels: From 0caa8fe7f58c7eb0a23a3bb46de00406bcc882b5 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Mon, 5 Jun 2023 13:56:54 +0300 Subject: [PATCH 05/26] second editorial review --- docs/generator_template.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index af7ac5800..a8417fbfc 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -240,7 +240,7 @@ New temperature detected 36947728 sent to temperature/changed New temperature detected 72955029 sent to temperature/changed ``` -To make sure your client works, also test it using an [MQTT CLI](https://hivemq.github.io/mqtt-cli/) using docker. Run the command `docker run hivemq/mqtt-cli sub -t comment/liked -h test.mosquitto.org` on your teminal. It will download the image if you don't have it locally then the CLI will conncet to the broker, subscribe to the `temperature/changed` topic and then output the temperature ids on the terminal. +To make sure your client works, also test it using an [MQTT CLI](https://hivemq.github.io/mqtt-cli/) using docker. Run the command `docker run hivemq/mqtt-cli sub -t temperature/changed -h test.mosquitto.org` on your teminal. It will download the image if you don't have it locally then the CLI will conncet to the broker, subscribe to the `temperature/changed` topic and then output the temperature ids on the terminal. ### 3.Update the template with client code @@ -476,7 +476,7 @@ function getTopics(channels) { } ``` -`{ channels }`:the TopicFunction component accepts a custom prop called channels and in your template code, you can call the comment as shown in the snippet below: +`{ 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. 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: @@ -565,4 +565,4 @@ Temperature rise detected 66943992 sent to temperature/risen ## Conclusion -In this tutorial, we have created a simple AsyncAPI generator template that uses a Python MQTT client. We have explained how to use an AsyncAPI file, create an python MQTT template and use them to generate code from it and use the Paho-MQTT library in Python to connect to an MQTT broker and publish messages. We hope this tutorial has helped you understand how to create the template. +In this tutorial, we have created a simple AsyncAPI generator template that uses a Python MQTT client. We have explained how to use an AsyncAPI file, create an python MQTT template and use them to generate code from it and use the Paho-MQTT library in Python to connect to an MQTT broker and publish messages. We hope this tutorial has helped you understand how to create a user-defined template. From 1fcf91a0c30d1ef5508f6f7493d13a8f8a5bf717 Mon Sep 17 00:00:00 2001 From: Florence Njeri <40742916+Florence-Njeri@users.noreply.github.com> Date: Wed, 28 Jun 2023 21:05:41 +0300 Subject: [PATCH 06/26] Update docs/generator_template.md Co-authored-by: V Thulisile Sibanda <66913810+thulieblack@users.noreply.github.com> --- docs/generator_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index a8417fbfc..a1096f2ad 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -3,7 +3,7 @@ title: "How to create a simple generator template" weight: 170 --- -In this tutorial, you'll learn to create a simple generator template using a python MQTT client. You'll use the AsyncAPI document and the template you develop to generate python code. Additionally, you'll create template code with a reusable component to reuse the custom functionality you create and test your code using an MQTT client. +In this tutorial, you'll learn to create a simple generator template using a Python MQTT client. You'll use the AsyncAPI document and the template you develop to generate Python code. Additionally, you'll create template code with a reusable component to reuse the custom functionality you create and test your code using an MQTT client. Let's suppose that you can only sleep when the AC in your bedroon is set to 22 °C and any you can't when the temperature drops or rises above that. You can install a smart monitor in your bedroom that keeps track of the temperature and notifies you to adjust your bedroom to your optimum temperature if it flactuates. You will create a template that sends alerts to notify you when the temperature fluctates from 22 °C. From 1e591c5a1c7827839b5c3e3f829e19bed039226d Mon Sep 17 00:00:00 2001 From: Florence Njeri <40742916+Florence-Njeri@users.noreply.github.com> Date: Wed, 28 Jun 2023 21:11:42 +0300 Subject: [PATCH 07/26] Apply suggestions from code review Co-authored-by: V Thulisile Sibanda <66913810+thulieblack@users.noreply.github.com> --- docs/generator_template.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index a1096f2ad..bd6207aa1 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -5,19 +5,19 @@ weight: 170 In this tutorial, you'll learn to create a simple generator template using a Python MQTT client. You'll use the AsyncAPI document and the template you develop to generate Python code. Additionally, you'll create template code with a reusable component to reuse the custom functionality you create and test your code using an MQTT client. -Let's suppose that you can only sleep when the AC in your bedroon is set to 22 °C and any you can't when the temperature drops or rises above that. You can install a smart monitor in your bedroom that keeps track of the temperature and notifies you to adjust your bedroom to your optimum temperature if it flactuates. You will create a template that sends alerts to notify you when the temperature fluctates from 22 °C. +Suppose you can only sleep when the AC in your bedroom is set to 22 °C, and you can't see when the temperature drops or rises above that. You can install a smart monitor in your bedroom that keeps track of the temperature and notifies you to adjust it to your optimum temperature if it fluctuates. You will create a template that alerts you when the temperature fluctuates from 22 °C. In this tutorial: -- You'll use the [Eclipse Mosquito](https://test.mosquitto.org) **MQTT broker** which you'll connect to to subscribe and publish messages using an MQTT client. +- 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 [Python Paho-MQTT](https://pypi.org/project/paho-mqtt/) as the **MQTT client** in this project. - Lastly, you will 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. -- Create a reusable component to create the rise/dropped temperature functions in the output code. +- Create a reusable component for the output code's rise/dropped temperature functions. ## Background context -There is a list of [community maintained templates](https://www.asyncapi.com/docs/tools/generator/template#generator-templates-list) but what if you require customized output from the generator? In that case, you'll create a user-defined template that generates custom output from the generator. -Before you create the template, you'll need to have an [asyncapi document](https://www.asyncapi.com/docs/tools/generator/asyncapi-document),that defines the properties you want to use in your template, to test the template against. In this tutorial, you'll use the following template saved in `test/fixtures/asyncapi.yml` file in your template project directory. +There is a list of [community maintained templates](https://www.asyncapi.com/docs/tools/generator/template#generator-templates-list), but what if you require customized output from the generator? In that case, you'll create a user-defined template that generates custom output from the generator. +Before you create the template, you'll need to have an [AsyncAPI document](https://www.asyncapi.com/docs/tools/generator/asyncapi-document) that defines the properties you want to use in your template to test against. In this tutorial, you'll use the following template saved in the `test/fixtures/asyncapi.yml` file in your template project directory. ``` yml From 8f10260d743812609f4b3213847c58207939513d Mon Sep 17 00:00:00 2001 From: Florence Njeri <40742916+Florence-Njeri@users.noreply.github.com> Date: Wed, 28 Jun 2023 21:12:56 +0300 Subject: [PATCH 08/26] Apply suggestions from code review Co-authored-by: V Thulisile Sibanda <66913810+thulieblack@users.noreply.github.com> --- docs/generator_template.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index bd6207aa1..e8064c2ef 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -62,8 +62,8 @@ components: Note: - To generate code, you will use the [asyncapi cli](https://www.asyncapi.com/tools/cli). If you don't have the CLI installed follow [this guide](https://www.asyncapi.com/docs/tools/generator/installation-guide#asyncapi-cli). -- If you are new to asyncapi, checkout the following docs: [template development](https://www.asyncapi.com/docs/tools/generator/template-development) which explains the minimum requirements for a template and possible features. -- Learn more about asyncronous messaging using MQTT [here](https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4). +- If you are new to AsyncAPI, check out the following docs: [template development](https://www.asyncapi.com/docs/tools/generator/template-development), which explains the minimum requirements for a template and possible features. +- You can [learn more about asynchronous messaging using MQTT](https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4). ## Steps followed to create a template @@ -150,7 +150,7 @@ Generation in progress. Keep calm and wait a bit... done Check out your shiny new generated files at output. ``` -And navigating to the **project** directory, you should see a **client.py** file and the only content is Temperature Service. +And navigating to the **project** directory, you should see a **client.py** file; the only content is Temperature Service. Let's break down the previous command: @@ -161,7 +161,7 @@ Let's break down the previous command: ## Creating a template -We will create an MQTT supported template that will generate a python client from the template and the asyncAPI document above. +We will create an MQTT-supported template that will generate a Python client from the template and the AsyncAPI document above. In this section, you'll: @@ -199,14 +199,14 @@ class TemperatureServiceClient: Make sure you have the paho-mqtt library installed. You can install it using pip with the `pip install paho-mqtt` command. Let's break down the previous code snippet: -1. Imports the mqtt module from the paho package, which provides the MQTT client functionality. -2. Assigns the MQTT broker address `test.mosquitto.org` to the variable mqttBroker. This specifies the location where the MQTT client will connect to. +1. Imports the MQTT module from the paho package, which provides the MQTT client functionality. +2. Assigns the MQTT broker address `test.mosquitto.org` to the variable MQTT broker. This specifies the location where the MQTT client will connect to. 3. Creates an instance of the MQTT client object. This object will be used to establish a connection with the MQTT broker and perform MQTT operations. 4. Establishes a connection to the MQTT broker. This command connects the MQTT client to the broker. 5. The MQTT topic to which the client will publish messages. 6. This command publishes the temperature change information to the MQTT broker. -In summary, this code sets up an MQTT client using the paho-MQTT library. It connects to the `test.mosquitto.or`g MQTT broker, and the `sendTemperatureChange()` method publishes temperature change information to the `temperature/changed` topic whenever called. +In summary, this code sets up an MQTT client using the paho-MQTT library. It connects to the `test.mosquitto.org` MQTT broker, and the `sendTemperatureChange()` method publishes temperature change information to the `temperature/changed` topic whenever called. ### 2.Test the client @@ -296,7 +296,7 @@ Run `npm test` on your terminal to ensure everything works as expected. ### Add parameters to the configuration file -In programming we often have different runtime environments e.g development and production. You will use different servers to spin both of these instances. In your case, you'll probably have two broker versions one for use in production and the other in development. You have defined a dev server in the AsyncAPI document: +We often have different runtime environments in programming, e.g., development and production. You will use different servers to spin both of these instances. You'll probably have two broker versions, one for production and the other for development. You have defined a dev server in the AsyncAPI document: ```yml servers: @@ -311,7 +311,7 @@ servers: This will allow you to also define the broker you will use in production in the servers section above. Therefore, we can template the code `mqttBroker = 'test.mosquitto.org'` in **index.js** so the value is populated dynamically at runtime depending on the specified server environment. -Generator has a **parameters** object used to define parameters you use to dynamically to modify your template code at runtime. It also supports the **server** parameter that defines the server configuration value. Navigate to **package.json** and add the snippet below: +The generator has a **parameters** object used to define parameters you use to dynamically modify your template code at runtime. It also supports the **server** parameter that defines the server configuration value. Navigate to **package.json** and add the snippet below: ```json "generator": { @@ -332,17 +332,17 @@ You'll pass the server to be used to generate your code using `--param server=de Generator Error: This template requires the following missing params: server. ``` -Update your `test:generate` script in `package.json` to inlcude the server param `test:generate": "asyncapi generate fromTemplate test/fixtures/asyncapi.yml ./ --output test/project --force-write --param server=dev "` +Update your `test:generate` script in `package.json` to include the server param `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**. -Now the template code looks like: +Now the template code looks like this: ``` js import { File } from '@asyncapi/generator-react-sdk'; // notice that now the template not only gets the instance of parsed AsyncAPI document but also the parameters -export default function ({ asyncapi }) { - console.log(asyncapi, params) +export default function ({ asyncapi, params }) { + return ( {`import paho.mqtt.client as mqtt @@ -367,7 +367,7 @@ Run `npm test` to validate that your code still works as expected. ### Templating index.js with React -Python takes indentation very seriously and out generated output will be python code. We therefpre need to make sure the indentation in index.js looks right so the generated code is indented properly. After templating the code in index.js, it will look like the following code snippet: +Python takes indentation very seriously, and our generated output will be Python code. We, therefore, need to make sure the indentation in index.js looks right so the generated code is indented correctly. After templating the code in index.js, it will look like the following code snippet: ```js // 1 @@ -387,6 +387,7 @@ export default function ({ asyncapi, params }) { self.client = mqtt.Client() self.client.connect(mqttBroker)`} + ) } ``` @@ -397,7 +398,7 @@ export default function ({ asyncapi, params }) { 4. Dynamically get the class name **TemperatureServiceClient** from the AsyncAPI document from the **info** object using the Parser API using the code: `asyncapi.info().title()` . It will return `Temperature Service`, then remove the spaces and add Client as a suffix. 5. There is no templating needed in the `__init__` function, there is only hardcoded information. -> If you're on the fence about which templating engine you should use in your template, check out the [react render engine](https://www.asyncapi.com/docs/tools/generator/react-render-engine) and [nunjucks render engine](https://www.asyncapi.com/docs/tools/generator/nunjucks-render-engine) documentation. +> If you're on the fence about which templating engine you should use in your template, check out the [React render engine](https://www.asyncapi.com/docs/tools/generator/react-render-engine) and [nunjucks render engine](https://www.asyncapi.com/docs/tools/generator/nunjucks-render-engine) documentation. In the next section, you'll refactor your template to use React. ### Creating a reusable component @@ -565,4 +566,4 @@ Temperature rise detected 66943992 sent to temperature/risen ## Conclusion -In this tutorial, we have created a simple AsyncAPI generator template that uses a Python MQTT client. We have explained how to use an AsyncAPI file, create an python MQTT template and use them to generate code from it and use the Paho-MQTT library in Python to connect to an MQTT broker and publish messages. We hope this tutorial has helped you understand how to create a user-defined template. +In this tutorial, we have created a simple AsyncAPI generator template that uses a Python MQTT client. We have explained how to use an AsyncAPI file, create a Python MQTT template and use them to generate code from it, and use the Paho-MQTT library in Python to connect to an MQTT broker and publish messages. We hope this tutorial has helped you understand how to create a user-defined template. From 2751f7422bada30ef65a63344309c719c97053bc Mon Sep 17 00:00:00 2001 From: Florence Njeri <40742916+Florence-Njeri@users.noreply.github.com> Date: Wed, 28 Jun 2023 21:13:28 +0300 Subject: [PATCH 09/26] Update docs/generator_template.md Co-authored-by: V Thulisile Sibanda <66913810+thulieblack@users.noreply.github.com> --- docs/generator_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index e8064c2ef..5dbe44046 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -61,7 +61,7 @@ components: Note: -- To generate code, you will use the [asyncapi cli](https://www.asyncapi.com/tools/cli). If you don't have the CLI installed follow [this guide](https://www.asyncapi.com/docs/tools/generator/installation-guide#asyncapi-cli). +- To generate code, use the [AsyncAPI CLI](https://www.asyncapi.com/tools/cli). If you don't have the CLI installed, follow [this guide](https://www.asyncapi.com/docs/tools/generator/installation-guide#asyncapi-cli). - If you are new to AsyncAPI, check out the following docs: [template development](https://www.asyncapi.com/docs/tools/generator/template-development), which explains the minimum requirements for a template and possible features. - You can [learn more about asynchronous messaging using MQTT](https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4). From b9e76d71f53a38ccb34b43042f7b9971111bcba2 Mon Sep 17 00:00:00 2001 From: Florence Njeri <40742916+Florence-Njeri@users.noreply.github.com> Date: Tue, 4 Jul 2023 10:12:31 +0300 Subject: [PATCH 10/26] Apply suggestions from code review Add editorial suggestions Co-authored-by: Lukasz Gornicki --- docs/generator_template.md | 65 +++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index 5dbe44046..971dd27ea 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -16,7 +16,7 @@ In this tutorial: ## Background context -There is a list of [community maintained templates](https://www.asyncapi.com/docs/tools/generator/template#generator-templates-list), but what if you require customized output from the generator? In that case, you'll create a user-defined template that generates custom output from the generator. +There is a list of [community maintained templates](https://www.asyncapi.com/docs/tools/generator/template#generator-templates-list), but what if you do not find what you need? In that case, you'll create a user-defined template that generates custom output from the generator. Before you create the template, you'll need to have an [AsyncAPI document](https://www.asyncapi.com/docs/tools/generator/asyncapi-document) that defines the properties you want to use in your template to test against. In this tutorial, you'll use the following template saved in the `test/fixtures/asyncapi.yml` file in your template project directory. ``` yml @@ -32,9 +32,6 @@ servers: dev: url: test.mosquitto.org protocol: mqtt - bindings: - mqtt: - clientId: temperature-service channels: temperature/changed: @@ -61,8 +58,8 @@ components: Note: -- To generate code, use the [AsyncAPI CLI](https://www.asyncapi.com/tools/cli). If you don't have the CLI installed, follow [this guide](https://www.asyncapi.com/docs/tools/generator/installation-guide#asyncapi-cli). -- If you are new to AsyncAPI, check out the following docs: [template development](https://www.asyncapi.com/docs/tools/generator/template-development), which explains the minimum requirements for a template and possible features. +- To generate code, use the [AsyncAPI CLI](https://www.asyncapi.com/tools/cli). If you don't have the CLI installed, follow [CLI installation guide](/docs/tools/cli/installation). +- If you are new to AsyncAPI Generator, check out the following docs: [template development](/docs/tools/generator/template-development), which explains the minimum requirements for a template and possible features. - You can [learn more about asynchronous messaging using MQTT](https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4). ## Steps followed to create a template @@ -129,7 +126,7 @@ export default function ({ asyncapi }) { The code snippet above does the following: 1. Import the `generator-react-sdk` dependency. -2. The `asyncapi` argument is an instance of the [AsyncAPI Parser](https://www.asyncapi.com/docs/tools/generator/parser). It will allow you to access the content of the asyncapi document in your template using helper functions. +2. The `asyncapi` argument is an instance of the [AsyncAPI Parser](https://www.asyncapi.com/docs/tools/generator/parser). It will allow you to access the content of the AsyncAPI document in your template using helper functions. 3. The `asyncapi.info().title()` is using the info() helper function to return the info object from the AsyncAPI document illustrated in the code snippet below: ``` json @@ -139,7 +136,7 @@ info: description: This service is in charge of processing all the events related to temperature. ``` -`asyncapi.info().title()` will return Temperature Service. +`asyncapi.info().title()` returns `Temperature Service`. ### Test using AsyncAPI CLI @@ -150,25 +147,25 @@ Generation in progress. Keep calm and wait a bit... done Check out your shiny new generated files at output. ``` -And navigating to the **project** directory, you should see a **client.py** file; the only content is Temperature Service. +And navigating to the **test/project** directory, you should see a **client.py** file; the only content is `Temperature Service`. Let's break down the previous command: - `asyncapi generate fromTemplate` is how you use AsyncAPI generator via the AsyncAPI CLI. -- `asyncapi.yaml` points to your AsyncAPI document. +- `test/fixtures/asyncapi.yml` points to your AsyncAPI document. - `./` specifies the location of your template. - `-o` determines where to output the result. ## Creating a template -We will create an MQTT-supported template that will generate a Python client from the template and the AsyncAPI document above. +You will create an MQTT-supported template that will generate a Python client from the template and the AsyncAPI document above. In this section, you'll: 1. Write the MQTT client code. -2. Write code to test the client works +2. Write code to test the client works. 3. Update the template to use the client code. -4. Setup a script to help you run this code +4. Setup a script to help you run this code. 5. Template your code. ## 1. Create the client @@ -201,14 +198,13 @@ Let's break down the previous code snippet: 1. Imports the MQTT module from the paho package, which provides the MQTT client functionality. 2. Assigns the MQTT broker address `test.mosquitto.org` to the variable MQTT broker. This specifies the location where the MQTT client will connect to. -3. Creates an instance of the MQTT client object. This object will be used to establish a connection with the MQTT broker and perform MQTT operations. -4. Establishes a connection to the MQTT broker. This command connects the MQTT client to the broker. -5. The MQTT topic to which the client will publish messages. -6. This command publishes the temperature change information to the MQTT broker. +3. Defines an instance of the MQTT client object. This object will be used to establish a connection with the MQTT broker and perform MQTT operations. +4. Defines that on client instance creation, it connects to the broker. +5. The `sendTemperatureChange` is a function that client user invokes to publish a message to the broker, and its specific topic. In summary, this code sets up an MQTT client using the paho-MQTT library. It connects to the `test.mosquitto.org` MQTT broker, and the `sendTemperatureChange()` method publishes temperature change information to the `temperature/changed` topic whenever called. -### 2.Test the client +### 2. Test the client You'll interact with the Temperature Service using the client module you created above. You'll create an instance of the client using `client = TemperatureServiceClient()` and then use `client.sendTemperatureChange` function to publish messages that Temperature Service is subscribed to. Create a **test/project/test.py** file in your project and add the code snippet below: @@ -232,7 +228,7 @@ while True: ``` -Run the code above on your terminal using the command `python test.py`. You'll should see output similar to the snippet below logged on your terminal: +Run the code above in your terminal using the command `python test.py`. You should see output similar to the snippet below logged on your terminal: ``` cmd New temperature detected 64250266 sent to temperature/changed @@ -240,9 +236,9 @@ New temperature detected 36947728 sent to temperature/changed New temperature detected 72955029 sent to temperature/changed ``` -To make sure your client works, also test it using an [MQTT CLI](https://hivemq.github.io/mqtt-cli/) using docker. Run the command `docker run hivemq/mqtt-cli sub -t temperature/changed -h test.mosquitto.org` on your teminal. It will download the image if you don't have it locally then the CLI will conncet to the broker, subscribe to the `temperature/changed` topic and then output the temperature ids on the terminal. +To make sure your `test.py` and client code works check if the broker really receives temperature-related messages. You can do it using an [MQTT CLI](https://hivemq.github.io/mqtt-cli/) using docker. Run the command `docker run hivemq/mqtt-cli sub -t temperature/changed -h test.mosquitto.org` in your terminal. It will download the image if you don't have it locally, then the CLI will connect to the broker, subscribe to the `temperature/changed` topic and then output the temperature ids on the terminal. -### 3.Update the template with client code +### 3. Update the template with client code Open **index.js** and copy the content of **client.py** and replace `{asyncapi.info().title()}` with it. It should look like the code snippet below now: @@ -285,10 +281,10 @@ In **package.json** you can have the scripts property that you invoke by calling The 4 scripts above do the following: -1. `test:clean`: This script uses the rimraf package to remove the old version of the file **test/project/client.py** everytime you run your test. -2. `test:generate`: This script uses the AsyncAPI CLI to generate a new version of **client.py** -3. `test:start`: This script runs the python code using **client.py** -4. `test`: This script runs `npm test` to check that everything is working as expected. +1. `test:clean`: This script uses the `rimraf` package to remove the old version of the file **test/project/client.py** every time you run your test. +2. `test:generate`: This script uses the AsyncAPI CLI to generate a new version of **client.py**. +3. `test:start`: This script runs the python code using **client.py**. +4. `test`: This script runs all the other scripts in proper order. Run `npm test` on your terminal to ensure everything works as expected. @@ -296,16 +292,13 @@ Run `npm test` on your terminal to ensure everything works as expected. ### Add parameters to the configuration file -We often have different runtime environments in programming, e.g., development and production. You will use different servers to spin both of these instances. You'll probably have two broker versions, one for production and the other for development. You have defined a dev server in the AsyncAPI document: +You often have different runtime environments in programming, e.g., development and production. You will use different servers to spin both of these instances. You'll probably have two broker versions, one for production and the other for development. You have defined a dev server in the AsyncAPI document: ```yml servers: dev: url: test.mosquitto.org protocol: mqtt - bindings: - mqtt: - clientId: temperature-service ``` This will allow you to also define the broker you will use in production in the servers section above. @@ -332,7 +325,7 @@ You'll pass the server to be used to generate your code using `--param server=de Generator Error: This template requires the following missing params: server. ``` -Update your `test:generate` script in `package.json` to include the server param `test:generate": "asyncapi generate fromTemplate test/fixtures/asyncapi.yml ./ --output test/project --force-write --param server=dev "` +Update your `test:generate` script in `package.json` to include the server param `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**. Now the template code looks like this: @@ -394,8 +387,8 @@ export default function ({ asyncapi, params }) { 1. Import the **Text** component that will wrap strings so they are indented properly in the output. Your import statement should now look like this: `import { File, Text } from '@asyncapi/generator-react-sdk'`. 2. When the paho module import is rendered in **client.py** file, it will add two extra new lines. -3. The broker url is templated in a Text component removing the `$` from the string template. -4. Dynamically get the class name **TemperatureServiceClient** from the AsyncAPI document from the **info** object using the Parser API using the code: `asyncapi.info().title()` . It will return `Temperature Service`, then remove the spaces and add Client as a suffix. +3. The broker url is templated in a `Text` component removing the `$` from the string template. +4. Dynamically get the class name **TemperatureServiceClient** from the AsyncAPI document from the **info** object using the Parser API using the code: `asyncapi.info().title()` . It will return `Temperature Service`, then remove the spaces and add `Client` as a suffix. 5. There is no templating needed in the `__init__` function, there is only hardcoded information. > If you're on the fence about which templating engine you should use in your template, check out the [React render engine](https://www.asyncapi.com/docs/tools/generator/react-render-engine) and [nunjucks render engine](https://www.asyncapi.com/docs/tools/generator/nunjucks-render-engine) documentation. @@ -417,7 +410,7 @@ class TemperatureServiceClient: self.client.connect(mqttBroker) def sendTemperatureDrop(self, id): - topic = "temperature/droped" + topic = "temperature/dropped" self.client.publish(topic, id) def sendTemperatureRise(self, id): topic = "temperature/risen" @@ -477,10 +470,10 @@ function getTopics(channels) { } ``` -`{ 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. +`{ 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. -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: +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: ```js import { File, Text } from '@asyncapi/generator-react-sdk' From bab252db4c88bc4146a1cd134faf0ff1569476e3 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Thu, 6 Jul 2023 07:46:19 +0300 Subject: [PATCH 11/26] add the note component --- docs/generator_template.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index a8417fbfc..bf894ed41 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -59,12 +59,14 @@ components: type: string ``` -Note: + - To generate code, you will use the [asyncapi cli](https://www.asyncapi.com/tools/cli). If you don't have the CLI installed follow [this guide](https://www.asyncapi.com/docs/tools/generator/installation-guide#asyncapi-cli). - If you are new to asyncapi, checkout the following docs: [template development](https://www.asyncapi.com/docs/tools/generator/template-development) which explains the minimum requirements for a template and possible features. - Learn more about asyncronous messaging using MQTT [here](https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4). + + ## Steps followed to create a template 1. Create a new directory for your template named **python-mqtt-client-template**. From 90a1626f4e939d65a9b54392c4bdcf1d558313eb Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Thu, 6 Jul 2023 07:57:50 +0300 Subject: [PATCH 12/26] mention adding test.py in the overview and rimraf devDependencies --- docs/generator_template.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index 798ad59ad..bc46787c0 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -64,15 +64,14 @@ components: -## Steps followed to create a template +## Overview of steps you follow to create a template 1. Create a new directory for your template named **python-mqtt-client-template**. 2. Install the AsyncAPI CLI using the command `npm install -g @asyncapi/cli`. 3. Create a new folder **test/fixtures** with a file named `asyncapi.yml` in your fixtures directory. This file is used to define the **structure** of your template. 4. Create a new file named `package.json` in your template directory. This file is used to define the **dependencies** for your template. 5. Create a new file named `index.js` in your **template** directory. This file is used to define the **logic** for your template. -6. Create a new directory named `partials` in your template directory. This directory is used to store the **partial HTML** files that are used to create the final documentation. -7. Create a new directory named `assets` in your template directory. This directory is used to **store the CSS and JavaScript files that are used to style the final documentation or website**. +6. Create a `test.py` file to validate the logic of your application. Lets break it down: @@ -93,6 +92,9 @@ The `package.json` file is used to define the dependencies for your template. He }, "dependencies": { "@asyncapi/generator-react-sdk": "^0.2.25" + }, + "devDependencies": { + "rimraf": "^5.0.0" } } ``` From b006a53cd0c8a00022f8a15ef14a8b5cbff9a985 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Sat, 8 Jul 2023 07:21:06 +0300 Subject: [PATCH 13/26] fix Paho case --- docs/generator_template.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index bc46787c0..8783e4321 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -174,7 +174,7 @@ In this section, you'll: ## 1. Create the client -The following code is an example of a Python client using the paho-MQTT library: +The following code is an example of a Python client using the Paho-MQTT library: ``` python # 1 @@ -197,16 +197,16 @@ class TemperatureServiceClient: self.client.publish(topic, id) ``` -Make sure you have the paho-mqtt library installed. You can install it using pip with the `pip install paho-mqtt` command. +Make sure you have the Paho-mqtt library installed. You can install it using pip with the `pip install paho-mqtt` command. Let's break down the previous code snippet: -1. Imports the MQTT module from the paho package, which provides the MQTT client functionality. +1. Imports the MQTT module from the Paho package, which provides the MQTT client functionality. 2. Assigns the MQTT broker address `test.mosquitto.org` to the variable MQTT broker. This specifies the location where the MQTT client will connect to. 3. Defines an instance of the MQTT client object. This object will be used to establish a connection with the MQTT broker and perform MQTT operations. 4. Defines that on client instance creation, it connects to the broker. 5. The `sendTemperatureChange` is a function that client user invokes to publish a message to the broker, and its specific topic. -In summary, this code sets up an MQTT client using the paho-MQTT library. It connects to the `test.mosquitto.org` MQTT broker, and the `sendTemperatureChange()` method publishes temperature change information to the `temperature/changed` topic whenever called. +In summary, this code sets up an MQTT client using the Paho-MQTT library. It connects to the `test.mosquitto.org` MQTT broker, and the `sendTemperatureChange()` method publishes temperature change information to the `temperature/changed` topic whenever called. ### 2. Test the client @@ -390,7 +390,7 @@ export default function ({ asyncapi, params }) { ``` 1. Import the **Text** component that will wrap strings so they are indented properly in the output. Your import statement should now look like this: `import { File, Text } from '@asyncapi/generator-react-sdk'`. -2. When the paho module import is rendered in **client.py** file, it will add two extra new lines. +2. When the Paho module import is rendered in **client.py** file, it will add two extra new lines. 3. The broker url is templated in a `Text` component removing the `$` from the string template. 4. Dynamically get the class name **TemperatureServiceClient** from the AsyncAPI document from the **info** object using the Parser API using the code: `asyncapi.info().title()` . It will return `Temperature Service`, then remove the spaces and add `Client` as a suffix. 5. There is no templating needed in the `__init__` function, there is only hardcoded information. From 0f19b23435ef86f0930193e3d054e9c9ff78ffe5 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Sat, 8 Jul 2023 07:23:30 +0300 Subject: [PATCH 14/26] match function names to the code --- docs/generator_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index 8783e4321..b68442789 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -422,7 +422,7 @@ class TemperatureServiceClient: ``` -You'll then need to template to dynamically generate `sendTemperatureDropped` and `sendTemperatureRisen` 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 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: ```js From a707f598f886927c5a39c20a1800cb913707dcef Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Sat, 8 Jul 2023 07:26:22 +0300 Subject: [PATCH 15/26] fix TopicVariable --- docs/generator_template.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index b68442789..f0e12d411 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -426,11 +426,11 @@ You'll then need to template to dynamically generate `sendTemperatureDrop` and ` ```js - + ``` -It's recommended to put reusable components outside 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 contain a `publish` operation. Add the following code in **components/TopicFunctions.js** file: +It's recommended to put reusable components outside 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 contain a `publish` operation. Add the following code in **components/TopicFunction.js** file: ```js /* From 0aa2f68ad3349b564c2212788425964c5d6069c6 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Sat, 8 Jul 2023 08:22:20 +0300 Subject: [PATCH 16/26] add a where to go from here section --- docs/generator_template.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index f0e12d411..ec2bc4d2d 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -561,6 +561,8 @@ Temperature drop detected 66943992 sent to temperature/dropped Temperature rise detected 66943992 sent to temperature/risen ``` -## Conclusion +## Where to go from here? -In this tutorial, we have created a simple AsyncAPI generator template that uses a Python MQTT client. We have explained how to use an AsyncAPI file, create a Python MQTT template and use them to generate code from it, and use the Paho-MQTT library in Python to connect to an MQTT broker and publish messages. We hope this tutorial has helped you understand how to create a user-defined template. +Great job completing this tutorial! You have learnt how to use an AsyncAPI file, create a Python MQTT template and use them to generate code from it, and use the Paho-MQTT library in Python to connect to an MQTT broker and publish messages.:] + +If you want to tinker with a completed template and see how it would look like in production, check out the [Paho-MQTT template](https://github.com/derberg/python-mqtt-client-template) developed by [Lukasz](https://github.com/derberg). You can also check out the accompanying [tutorial to create MQTT client code](https://derberg-github-io-git-articlecodegenpython-derberg.vercel.app/blog/asyncapi-codegen-python). From 4b0c0c9a95a1ab6cececf7aaad35338ccc68009c Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Sat, 8 Jul 2023 08:32:40 +0300 Subject: [PATCH 17/26] editorial review of the create the client section --- docs/generator_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index ec2bc4d2d..aac98afbe 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -174,7 +174,7 @@ In this section, you'll: ## 1. Create the client -The following code is an example of a Python client using the Paho-MQTT library: +The following is the sample code of the Python client you generated [above](#test-using-asyncapi-cli) using the Paho-MQTT library after running the `asyncapi generate fromTemplate test/fixtures/asyncapi.yml ./ -o test/project` command. ``` python # 1 From 02f3108c67ead840022fb6b0ee5d2baf644d5a35 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Sat, 8 Jul 2023 08:38:53 +0300 Subject: [PATCH 18/26] editorial review --- docs/generator_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index aac98afbe..0ce2130ad 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -172,7 +172,7 @@ In this section, you'll: 4. Setup a script to help you run this code. 5. Template your code. -## 1. Create the client +### 1. Create the client The following is the sample code of the Python client you generated [above](#test-using-asyncapi-cli) using the Paho-MQTT library after running the `asyncapi generate fromTemplate test/fixtures/asyncapi.yml ./ -o test/project` command. From 2e1f9e2f6ded1f08ee2ec3fd929814c67d611dac Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Mon, 10 Jul 2023 09:02:59 +0300 Subject: [PATCH 19/26] make file names bold instead of code blocks and move the MQTT tutorial to the where to go from here section --- docs/generator_template.md | 45 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index 0ce2130ad..f27bc74c9 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -5,19 +5,19 @@ weight: 170 In this tutorial, you'll learn to create a simple generator template using a Python MQTT client. You'll use the AsyncAPI document and the template you develop to generate Python code. Additionally, you'll create template code with a reusable component to reuse the custom functionality you create and test your code using an MQTT client. -Suppose you can only sleep when the AC in your bedroom is set to 22 °C, and you can't see when the temperature drops or rises above that. You can install a smart monitor in your bedroom that keeps track of the temperature and notifies you to adjust it to your optimum temperature if it fluctuates. You will create a template that alerts you when the temperature fluctuates from 22 °C. +Suppose you can only sleep when the AC in your bedroom is set to 22 °C, and you can't sleep when the temperature drops or rises above that. You can install a smart monitor in your bedroom that keeps track of the temperature and notifies you to adjust it to your optimum temperature when it fluctuates. You will create a template to alerts you when the bedroom's temperature fluctuates from 22 °C. 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 [Python Paho-MQTT](https://pypi.org/project/paho-mqtt/) as the **MQTT client** in this project. -- Lastly, you will 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. -- Create a reusable component for the output code's rise/dropped temperature functions. +- 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. ## Background context There is a list of [community maintained templates](https://www.asyncapi.com/docs/tools/generator/template#generator-templates-list), but what if you do not find what you need? In that case, you'll create a user-defined template that generates custom output from the generator. -Before you create the template, you'll need to have an [AsyncAPI document](https://www.asyncapi.com/docs/tools/generator/asyncapi-document) that defines the properties you want to use in your template to test against. In this tutorial, you'll use the following template saved in the `test/fixtures/asyncapi.yml` file in your template project directory. +Before you create the template, you'll need to have an [AsyncAPI document](https://www.asyncapi.com/docs/tools/generator/asyncapi-document) that defines the properties you want to use in your template to test against. In this tutorial, you'll use the following template saved in the **test/fixtures/asyncapi.yml** file in your template project directory. ``` yml @@ -58,26 +58,25 @@ components: -- To generate code, use the [AsyncAPI CLI](https://www.asyncapi.com/tools/cli). If you don't have the CLI installed, follow [CLI installation guide](/docs/tools/cli/installation). +- To generate code, use the [AsyncAPI CLI](https://www.asyncapi.com/tools/cli). If you don't have the CLI installed, follow [CLI installation guide](/docs/tools/generator/installation-guide#asyncapi-cli). - If you are new to AsyncAPI Generator, check out the following docs: [template development](/docs/tools/generator/template-development), which explains the minimum requirements for a template and possible features. -- You can [learn more about asynchronous messaging using MQTT](https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4). -## Overview of steps you follow to create a template +## Overview of steps to follow to create a template 1. Create a new directory for your template named **python-mqtt-client-template**. 2. Install the AsyncAPI CLI using the command `npm install -g @asyncapi/cli`. -3. Create a new folder **test/fixtures** with a file named `asyncapi.yml` in your fixtures directory. This file is used to define the **structure** of your template. -4. Create a new file named `package.json` in your template directory. This file is used to define the **dependencies** for your template. -5. Create a new file named `index.js` in your **template** directory. This file is used to define the **logic** for your template. -6. Create a `test.py` file to validate the logic of your application. +3. Create a new folder **test/fixtures** with a file named **asyncapi.yml** in your fixtures directory. This file is used to define the **structure** of your template. +4. Create a new file named **package.json** in your template directory. This file is used to define the **dependencies** for your template. +5. Create a new file named **index.js** in your **template** directory. This file is used to define the **logic** for your template. +6. Create a **test.py** file to validate the logic of your application. Lets break it down: -### `package.json` file +### package.json file -The `package.json` file is used to define the dependencies for your template. Here's an example `package.json` file: +The **package.json** file is used to define the dependencies for your template. Here's an example **package.json** file: ``` json { @@ -111,11 +110,11 @@ Here's what is contained in the code snippet above: - **supportedProtocols** - A list that specifies which protocols are supported by your template. - **dependencies** - specifies which version of [`@asyncapi/generator-react-sdk`](https://github.com/asyncapi/generator-react-sdk) should be used. -Run the command `npm install` on your terminal to install the dependencies specified in `package.json`. +Run the command `npm install` on your terminal to install the dependencies specified in **package.json**. -### `index.js` file +### index.js file -The index.js file is used to define the logic for your template. Inside the template folder, create an `index.js` file and add the code snippet below: +The **index.js** file is used to define the logic for your template. Inside the template folder, create an **index.js** file and add the code snippet below: ```js //1 @@ -240,7 +239,7 @@ New temperature detected 36947728 sent to temperature/changed New temperature detected 72955029 sent to temperature/changed ``` -To make sure your `test.py` and client code works check if the broker really receives temperature-related messages. You can do it using an [MQTT CLI](https://hivemq.github.io/mqtt-cli/) using docker. Run the command `docker run hivemq/mqtt-cli sub -t temperature/changed -h test.mosquitto.org` in your terminal. It will download the image if you don't have it locally, then the CLI will connect to the broker, subscribe to the `temperature/changed` topic and then output the temperature ids on the terminal. +To make sure your **test.py** and client code works check if the broker really receives temperature-related messages. You can do it using an [MQTT CLI](https://hivemq.github.io/mqtt-cli/) using docker. Run the command `docker run hivemq/mqtt-cli sub -t temperature/changed -h test.mosquitto.org` in your terminal. It will download the image if you don't have it locally, then the CLI will connect to the broker, subscribe to the `temperature/changed` topic and then output the temperature ids on the terminal. ### 3. Update the template with client code @@ -294,7 +293,7 @@ Run `npm test` on your terminal to ensure everything works as expected. ### 5. Template your code -### Add parameters to the configuration file +#### Add parameters to the configuration file You often have different runtime environments in programming, e.g., development and production. You will use different servers to spin both of these instances. You'll probably have two broker versions, one for production and the other for development. You have defined a dev server in the AsyncAPI document: @@ -329,7 +328,7 @@ You'll pass the server to be used to generate your code using `--param server=de Generator Error: This template requires the following missing params: server. ``` -Update your `test:generate` script in `package.json` to include the server param `test:generate": "asyncapi generate fromTemplate test/fixtures/asyncapi.yml ./ --output test/project --force-write --param server=dev"` +Update your `test:generate` script in **package.json** to include the server param `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**. Now the template code looks like this: @@ -362,7 +361,7 @@ class TemperatureServiceClient: Run `npm test` to validate that your code still works as expected. -### Templating index.js with React +#### Templating index.js with React Python takes indentation very seriously, and our generated output will be Python code. We, therefore, need to make sure the indentation in index.js looks right so the generated code is indented correctly. After templating the code in index.js, it will look like the following code snippet: @@ -398,7 +397,7 @@ export default function ({ asyncapi, params }) { > If you're on the fence about which templating engine you should use in your template, check out the [React render engine](https://www.asyncapi.com/docs/tools/generator/react-render-engine) and [nunjucks render engine](https://www.asyncapi.com/docs/tools/generator/nunjucks-render-engine) documentation. In the next section, you'll refactor your template to use React. -### Creating a reusable component +#### Creating a reusable component If you had two [channels](https://www.asyncapi.com/docs/concepts/channel), one to watch if the temperature drop below 22 °C and one to check if the temperature is above 22 °C, the generated output code would look like this: @@ -510,7 +509,7 @@ export default function ({ asyncapi, params }) { Run `npm test` on your terminal to ensure everything works as expected. Add another channel to asyncapi.yml file called `temperatureDropped` and `temperatureRisen` then run the template again to make sure it still works as expected. -#### Update AsyncAPi document +#### Update AsyncAPI document Update the AsyncAPI document to use two channels: @@ -566,3 +565,5 @@ Temperature rise detected 66943992 sent to temperature/risen Great job completing this tutorial! You have learnt how to use an AsyncAPI file, create a Python MQTT template and use them to generate code from it, and use the Paho-MQTT library in Python to connect to an MQTT broker and publish messages.:] If you want to tinker with a completed template and see how it would look like in production, check out the [Paho-MQTT template](https://github.com/derberg/python-mqtt-client-template) developed by [Lukasz](https://github.com/derberg). You can also check out the accompanying [tutorial to create MQTT client code](https://derberg-github-io-git-articlecodegenpython-derberg.vercel.app/blog/asyncapi-codegen-python). + +Check out the [MQTT beginners guide]((https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4)) tutorial to learn more about asynchronous messaging using MQTT. From fd7a138393011828572e9921361699c0c1947119 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Mon, 10 Jul 2023 09:47:12 +0300 Subject: [PATCH 20/26] final editorial review by author --- docs/generator_template.md | 42 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index f27bc74c9..625c9508e 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -76,7 +76,7 @@ Lets break it down: ### package.json file -The **package.json** file is used to define the dependencies for your template. Here's an example **package.json** file: +The **package.json** file is used to define the dependencies for your template. Add the following code snippet to your **package.json** file: ``` json { @@ -104,7 +104,7 @@ Here's what is contained in the code snippet above: - **version** - the current version of your template. - **description** - a description of what your template does. - **generator** - specify generator [specific configuration](https://www.asyncapi.com/docs/tools/generator/configuration-file). - - **renderer** - can either be `react` or `nunjucks`. In this case the generator will pass your template to the react render engine to generate the output. + - **renderer** - can either be [`react`](https://www.asyncapi.com/docs/tools/generator/react-render-engine) or [`nunjucks`](https://www.asyncapi.com/docs/tools/generator/nunjucks-render-engine). In this case the generator will pass your template to the react render engine to generate the output. - **apiVersion** - specifies which major version of the [Parser-API](https://github.com/asyncapi/parser-api) your template will use. - **generator** - a string representing the generator version-range your template is compatible with. - **supportedProtocols** - A list that specifies which protocols are supported by your template. @@ -121,7 +121,7 @@ The **index.js** file is used to define the logic for your template. Inside the import { File } from '@asyncapi/generator-react-sdk' //2 export default function ({ asyncapi }) { - //3 +//3 return {asyncapi.info().title()} } ``` @@ -139,7 +139,7 @@ info: description: This service is in charge of processing all the events related to temperature. ``` -`asyncapi.info().title()` returns `Temperature Service`. +The `asyncapi.info().title()` returns `Temperature Service`. ### Test using AsyncAPI CLI @@ -150,14 +150,14 @@ Generation in progress. Keep calm and wait a bit... done Check out your shiny new generated files at output. ``` -And navigating to the **test/project** directory, you should see a **client.py** file; the only content is `Temperature Service`. +Navigating to the **test/project** directory. You should see a **client.py** file; the only content is `Temperature Service`. Let's break down the previous command: - `asyncapi generate fromTemplate` is how you use AsyncAPI generator via the AsyncAPI CLI. - `test/fixtures/asyncapi.yml` points to your AsyncAPI document. - `./` specifies the location of your template. -- `-o` determines where to output the result. +- `-o` specifies where to output the result. ## Creating a template @@ -192,7 +192,7 @@ class TemperatureServiceClient: def sendTemperatureChange(self, id): # 5 topic = "temperature/changed" - # 6 + # 6 self.client.publish(topic, id) ``` @@ -203,7 +203,7 @@ Let's break down the previous code snippet: 2. Assigns the MQTT broker address `test.mosquitto.org` to the variable MQTT broker. This specifies the location where the MQTT client will connect to. 3. Defines an instance of the MQTT client object. This object will be used to establish a connection with the MQTT broker and perform MQTT operations. 4. Defines that on client instance creation, it connects to the broker. -5. The `sendTemperatureChange` is a function that client user invokes to publish a message to the broker, and its specific topic. +5. The `sendTemperatureChange` is a function the client user invokes to publish a message to the broker, and its specific topic. In summary, this code sets up an MQTT client using the Paho-MQTT library. It connects to the `test.mosquitto.org` MQTT broker, and the `sendTemperatureChange()` method publishes temperature change information to the `temperature/changed` topic whenever called. @@ -243,7 +243,7 @@ To make sure your **test.py** and client code works check if the broker really r ### 3. Update the template with client code -Open **index.js** and copy the content of **client.py** and replace `{asyncapi.info().title()}` with it. It should look like the code snippet below now: +Open [**index.js**](#indexjs-file) and copy the content of [**client.py**](#1-create-the-client) and replace `{asyncapi.info().title()}` with it. It should look like the code snippet below now: ``` js import { File } from '@asyncapi/generator-react-sdk'; @@ -271,7 +271,7 @@ class TemperatureServiceClient: ### 4. Write script to run the test code -In **package.json** you can have the scripts property that you invoke by calling `npm run `. Add these scripts to **package.json**: +In **package.json** you can have the scripts property that you invoke by calling `npm run `. Add these scripts to **package.json**: ``` json "scripts": { @@ -295,7 +295,7 @@ Run `npm test` on your terminal to ensure everything works as expected. #### Add parameters to the configuration file -You often have different runtime environments in programming, e.g., development and production. You will use different servers to spin both of these instances. You'll probably have two broker versions, one for production and the other for development. You have defined a dev server in the AsyncAPI document: +You often have different runtime environments in programming, e.g., development and production. You will use different servers to spin both of these instances. You'll have two broker versions, one for production and the other for development. You have defined a dev server in the AsyncAPI document: ```yml servers: @@ -328,7 +328,12 @@ You'll pass the server to be used to generate your code using `--param server=de Generator Error: This template requires the following missing params: server. ``` -Update your `test:generate` script in **package.json** to include the server param `test:generate": "asyncapi generate fromTemplate test/fixtures/asyncapi.yml ./ --output test/project --force-write --param server=dev"` +Update your `test:generate` script in **package.json** to include the server param + +```json +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**. Now the template code looks like this: @@ -363,7 +368,7 @@ Run `npm test` to validate that your code still works as expected. #### Templating index.js with React -Python takes indentation very seriously, and our generated output will be Python code. We, therefore, need to make sure the indentation in index.js looks right so the generated code is indented correctly. After templating the code in index.js, it will look like the following code snippet: +Python takes indentation very seriously, and our generated output will be Python code. We, therefore, need to make sure the indentation in **index.js** looks right so the generated code is indented correctly. After templating the code in **index.js**, it will look like the following code snippet: ```js // 1 @@ -399,7 +404,7 @@ In the next section, you'll refactor your template to use React. #### Creating a reusable component -If you had two [channels](https://www.asyncapi.com/docs/concepts/channel), one to watch if the temperature drop below 22 °C and one to check if the temperature is above 22 °C, the generated output code would look like this: +Suppose you have two [channels](https://www.asyncapi.com/docs/concepts/channel), one to watch if the temperature drop below 22 °C and one to check if the temperature is above 22 °C, the generated output code would look like this: ```python import paho.mqtt.client as mqtt @@ -507,7 +512,8 @@ export default function ({ asyncapi, params }) { ``` Run `npm test` on your terminal to ensure everything works as expected. -Add another channel to asyncapi.yml file called `temperatureDropped` and `temperatureRisen` 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 `temperature/dropped` and `temperature/risen` then run the template again to make sure it still works as expected. #### Update AsyncAPI document @@ -562,8 +568,8 @@ Temperature rise detected 66943992 sent to temperature/risen ## Where to go from here? -Great job completing this tutorial! You have learnt how to use an AsyncAPI file, create a Python MQTT template and use them to generate code from it, and use the Paho-MQTT library in Python to connect to an MQTT broker and publish messages.:] +Great job completing this tutorial! You have learnt how to use an AsyncAPI file to create a Python MQTT template and used it with the Paho-MQTT library in Python to connect to an MQTT broker and publish messages.:] -If you want to tinker with a completed template and see how it would look like in production, check out the [Paho-MQTT template](https://github.com/derberg/python-mqtt-client-template) developed by [Lukasz](https://github.com/derberg). You can also check out the accompanying [tutorial to create MQTT client code](https://derberg-github-io-git-articlecodegenpython-derberg.vercel.app/blog/asyncapi-codegen-python). +If you want to tinker with a completed template and see what it would look like in production, check out the [Paho-MQTT template](https://github.com/derberg/python-mqtt-client-template) developed by [Lukasz](https://github.com/derberg). You can also check out the accompanying [tutorial to create MQTT client code](https://derberg-github-io-git-articlecodegenpython-derberg.vercel.app/blog/asyncapi-codegen-python). -Check out the [MQTT beginners guide]((https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4)) tutorial to learn more about asynchronous messaging using MQTT. +You can also check out the [MQTT beginners guide]((https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4)) tutorial to learn more about asynchronous messaging using MQTT. From 19c7dab1b175c3b321e52c0d915621f27c94b2cf Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Mon, 10 Jul 2023 10:08:53 +0300 Subject: [PATCH 21/26] link the final MQTT template code from this tutorial --- docs/generator_template.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/generator_template.md b/docs/generator_template.md index 625c9508e..24362b19a 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -570,6 +570,8 @@ Temperature rise detected 66943992 sent to temperature/risen Great job completing this tutorial! You have learnt how to use an AsyncAPI file to create a Python MQTT template and used it with the Paho-MQTT library in Python to connect to an MQTT broker and publish messages.:] +You can download the final [MQTT template project](https://github.com/Florence-Njeri/MQTT-Template) from Github. + If you want to tinker with a completed template and see what it would look like in production, check out the [Paho-MQTT template](https://github.com/derberg/python-mqtt-client-template) developed by [Lukasz](https://github.com/derberg). You can also check out the accompanying [tutorial to create MQTT client code](https://derberg-github-io-git-articlecodegenpython-derberg.vercel.app/blog/asyncapi-codegen-python). You can also check out the [MQTT beginners guide]((https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4)) tutorial to learn more about asynchronous messaging using MQTT. From 1a61d13a7fb541f0886ebd821660a32f65fee7a5 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Mon, 10 Jul 2023 10:13:26 +0300 Subject: [PATCH 22/26] remove project link --- docs/generator_template.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index 24362b19a..625c9508e 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -570,8 +570,6 @@ Temperature rise detected 66943992 sent to temperature/risen Great job completing this tutorial! You have learnt how to use an AsyncAPI file to create a Python MQTT template and used it with the Paho-MQTT library in Python to connect to an MQTT broker and publish messages.:] -You can download the final [MQTT template project](https://github.com/Florence-Njeri/MQTT-Template) from Github. - If you want to tinker with a completed template and see what it would look like in production, check out the [Paho-MQTT template](https://github.com/derberg/python-mqtt-client-template) developed by [Lukasz](https://github.com/derberg). You can also check out the accompanying [tutorial to create MQTT client code](https://derberg-github-io-git-articlecodegenpython-derberg.vercel.app/blog/asyncapi-codegen-python). You can also check out the [MQTT beginners guide]((https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4)) tutorial to learn more about asynchronous messaging using MQTT. From 1cd0e45417f80b8b8fb61ea73bd151380cba7473 Mon Sep 17 00:00:00 2001 From: Florence Njeri <40742916+Florence-Njeri@users.noreply.github.com> Date: Thu, 13 Jul 2023 13:22:17 +0300 Subject: [PATCH 23/26] Apply suggestions from code review 2nd PR review Co-authored-by: V Thulisile Sibanda <66913810+thulieblack@users.noreply.github.com> Co-authored-by: Lukasz Gornicki --- docs/generator_template.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index 625c9508e..7c2cab5ca 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -3,9 +3,9 @@ title: "How to create a simple generator template" weight: 170 --- -In this tutorial, you'll learn to create a simple generator template using a Python MQTT client. You'll use the AsyncAPI document and the template you develop to generate Python code. Additionally, you'll create template code with a reusable component to reuse the custom functionality you create and test your code using an MQTT client. +This tutorial teaches you how to create a simple generator template using a Python MQTT client. You'll use the AsyncAPI document and the template you develop to generate Python code. Additionally, you'll create template code with a reusable component to reuse the custom functionality you create and test your code using an MQTT client. -Suppose you can only sleep when the AC in your bedroom is set to 22 °C, and you can't sleep when the temperature drops or rises above that. You can install a smart monitor in your bedroom that keeps track of the temperature and notifies you to adjust it to your optimum temperature when it fluctuates. You will create a template to alerts you when the bedroom's temperature fluctuates from 22 °C. +Suppose you can only sleep when the AC in your bedroom is set to 22 °C, and you can't sleep when the temperature drops or rises above that. You can install a smart monitor in your bedroom that keeps track of the temperature and notifies you to adjust it to your optimum temperature when it fluctuates. You will create a template to alert you when the bedroom's temperature fluctuates from 22 °C. In this tutorial: @@ -63,7 +63,7 @@ components: -## Overview of steps to follow to create a template +## Overview of steps 1. Create a new directory for your template named **python-mqtt-client-template**. 2. Install the AsyncAPI CLI using the command `npm install -g @asyncapi/cli`. @@ -196,7 +196,7 @@ class TemperatureServiceClient: self.client.publish(topic, id) ``` -Make sure you have the Paho-mqtt library installed. You can install it using pip with the `pip install paho-mqtt` command. +Make sure you have the Paho-MQTT library installed. You can install it using pip with the `pip install paho-mqtt` command. Let's break down the previous code snippet: 1. Imports the MQTT module from the Paho package, which provides the MQTT client functionality. @@ -570,6 +570,6 @@ Temperature rise detected 66943992 sent to temperature/risen Great job completing this tutorial! You have learnt how to use an AsyncAPI file to create a Python MQTT template and used it with the Paho-MQTT library in Python to connect to an MQTT broker and publish messages.:] -If you want to tinker with a completed template and see what it would look like in production, check out the [Paho-MQTT template](https://github.com/derberg/python-mqtt-client-template) developed by [Lukasz](https://github.com/derberg). You can also check out the accompanying [tutorial to create MQTT client code](https://derberg-github-io-git-articlecodegenpython-derberg.vercel.app/blog/asyncapi-codegen-python). +If you want to tinker with a completed template and see what it would look like in production, check out the [Paho-MQTT template](https://github.com/derberg/python-mqtt-client-template/tree/v1.0.0). You can also check out the accompanying [article about creating MQTT client code](https://www.brainfart.dev/blog/asyncapi-codegen-python). You can also check out the [MQTT beginners guide]((https://medium.com/python-point/mqtt-basics-with-python-examples-7c758e605d4)) tutorial to learn more about asynchronous messaging using MQTT. From 5c3e79c1cb165c38bed4c16d6c01301e7b9e70cf Mon Sep 17 00:00:00 2001 From: Florence Njeri <40742916+Florence-Njeri@users.noreply.github.com> Date: Sun, 16 Jul 2023 19:55:33 +0300 Subject: [PATCH 24/26] Update docs/generator_template.md --- docs/generator_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index 7c2cab5ca..fe2e041d5 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -1,5 +1,5 @@ --- -title: "How to create a simple generator template" +title: "Creating a generator template" weight: 170 --- From 76812bb5263f22431b7e37a991a32ab6cfcae24e Mon Sep 17 00:00:00 2001 From: Florence Njeri <40742916+Florence-Njeri@users.noreply.github.com> Date: Wed, 19 Jul 2023 12:33:08 +0300 Subject: [PATCH 25/26] Update docs/generator_template.md Co-authored-by: Lukasz Gornicki --- docs/generator_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index fe2e041d5..deb3d033d 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -1,5 +1,5 @@ --- -title: "Creating a generator template" +title: "Creating a Generator template" weight: 170 --- From 04d5af05b78021f9deef582887b134ead6e1a481 Mon Sep 17 00:00:00 2001 From: Florence-Njeri Date: Wed, 19 Jul 2023 12:36:22 +0300 Subject: [PATCH 26/26] number template your code section --- docs/generator_template.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/generator_template.md b/docs/generator_template.md index 625c9508e..da7bc9452 100644 --- a/docs/generator_template.md +++ b/docs/generator_template.md @@ -293,7 +293,7 @@ Run `npm test` on your terminal to ensure everything works as expected. ### 5. Template your code -#### Add parameters to the configuration file +#### 5a. Add parameters to the configuration file You often have different runtime environments in programming, e.g., development and production. You will use different servers to spin both of these instances. You'll have two broker versions, one for production and the other for development. You have defined a dev server in the AsyncAPI document: @@ -366,7 +366,7 @@ class TemperatureServiceClient: Run `npm test` to validate that your code still works as expected. -#### Templating index.js with React +#### 5b. Templating index.js with React Python takes indentation very seriously, and our generated output will be Python code. We, therefore, need to make sure the indentation in **index.js** looks right so the generated code is indented correctly. After templating the code in **index.js**, it will look like the following code snippet: @@ -402,7 +402,7 @@ export default function ({ asyncapi, params }) { > If you're on the fence about which templating engine you should use in your template, check out the [React render engine](https://www.asyncapi.com/docs/tools/generator/react-render-engine) and [nunjucks render engine](https://www.asyncapi.com/docs/tools/generator/nunjucks-render-engine) documentation. In the next section, you'll refactor your template to use React. -#### Creating a reusable component +#### 5c. Creating a reusable component Suppose you have two [channels](https://www.asyncapi.com/docs/concepts/channel), one to watch if the temperature drop below 22 °C and one to check if the temperature is above 22 °C, the generated output code would look like this: @@ -515,7 +515,7 @@ 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. -#### Update AsyncAPI document +#### 5d. Update AsyncAPI document Update the AsyncAPI document to use two channels: @@ -568,7 +568,7 @@ Temperature rise detected 66943992 sent to temperature/risen ## Where to go from here? -Great job completing this tutorial! You have learnt how to use an AsyncAPI file to create a Python MQTT template and used it with the Paho-MQTT library in Python to connect to an MQTT broker and publish messages.:] +Great job completing this tutorial! You have learnt how to use an AsyncAPI file to create a Python MQTT template and used it with the Paho-MQTT library in Python to connect to an MQTT broker and publish messages.😃 If you want to tinker with a completed template and see what it would look like in production, check out the [Paho-MQTT template](https://github.com/derberg/python-mqtt-client-template) developed by [Lukasz](https://github.com/derberg). You can also check out the accompanying [tutorial to create MQTT client code](https://derberg-github-io-git-articlecodegenpython-derberg.vercel.app/blog/asyncapi-codegen-python).