Introduction
In this tutorial, you get started with actual code and a sample real-world use case. Let's pretend you have a company called Smarty Lighting, and you install smart-city streetlight lighting systems. This smart lighting system is a use case of the Internet of things (IoT).
You will create a Smartylighting Streetlights API using Node.js and Mosquitto as the message broker. This API will allow you to manage city lights remotely.
You want to build a system that can turn streetlights on and off based on their environmental conditions:
You will implement an event-driven architecture (EDA) with a Message Broker in its "center."
Streetlights will publish information about their environmental lighting to the broker.
Your application will connect to the broker and receive a stream of events from all the streetlights reporting their conditions.
Your application decides based on events when to turn the streetlight off.
Your application is not aware of how many streetlights are publishing events - it just connects to the broker and receives all events.
You will learn about event-driven architecture, message brokers, pub/sub architecture, and creating an AsyncAPI file to describe your API and generate code from it.
Background Context
Event-driven architecture (EDA) is a design pattern built around the production, detection, and reaction to events that take place in time. Message brokers enable asynchronous communications between services so that the sending service need not wait for the receiving service’s reply. This allows interdependent services to “talk” with one another directly, even if they were written in different languages or implemented on different platforms.
In this tutorial, we'll look at an IoT use case: a Smart-City street lighting system. Pub/sub is appealing for IoT use cases due to two key features: support for flexible coupling between publishers/subscribers and inherent support for point-to-multipoint transmission. MQTT and DDS are two well-known protocols that are widely used in IoT applications.
Installation Guide
You'll use Node.js to code the APIs and Mosquitto as the message broker. The selected technology is irrelevant here, since everything explained in this tutorial is applicable to any other programming language and message brokers.
Before you proceed to the next stage, you'll need to download a few things:
Install Node.js (v15 or newer).
Install Git based on your Operating System:
Creating the AsyncAPI file
In this step, we will create an AsyncAPI file to describe your API. It will help you generate the code and the documentation later on.
1asyncapi: '2.5.0'
2info:
3 title: Streetlights API
4 version: '1.0.0'
5 description: |
6 The Smartylighting Streetlights API allows you
7 to remotely manage the city lights.
8 license:
9 name: Apache 2.0
10 url: 'https://www.apache.org/licenses/LICENSE-2.0'
11servers:
12 mosquitto:
13 url: mqtt://test.mosquitto.org
14 protocol: mqtt
15channels:
16 light/measured:
17 publish:
18 summary: Inform about environmental lighting conditions for a particular streetlight.
19 operationId: onLightMeasured
20 message:
21 name: LightMeasured
22 payload:
23 type: object
24 properties:
25 id:
26 type: integer
27 minimum: 0
28 description: Id of the streetlight.
29 lumens:
30 type: integer
31 minimum: 0
32 description: Light intensity measured in lumens.
33 sentAt:
34 type: string
35 format: date-time
36 description: Date and time when the message was sent.
Let's break it down into pieces:
1asyncapi: '2.5.0'
2info:
3 title: Streetlights API
4 version: '1.0.0'
5 description: |
6 The Smartylighting Streetlights API allows you
7 to remotely manage the city lights.
8 license:
9 name: Apache 2.0
10 url: 'https://www.apache.org/licenses/LICENSE-2.0'
- The
asyncapi
field indicates you use the AsyncAPI version 2.5.0. - The
info
field holds information about the API, such as its name, version, description, and license.
Now lets move all the way to the channels
section. This section is used to describe the event names your API will be publishing and/or subscribing to.
1channels:
2 light/measured:
3 publish:
4 summary: Inform about environmental lighting conditions for a particular streetlight.
5 operationId: onLightMeasured
In this example, light/measured
is the channel name the Streetlight API will subscribe
to (i.e, to interact with the Streetlight API you publish
to the broker). The operationId
property, describes what is the name of function or method that takes care of this functionality in the generated code. The payload
property is used to understand how the event should look like when publishing to that channel:
1 payload:
2 type: object
3 properties:
4 id:
5 type: integer
6 minimum: 0
7 description: Id of the streetlight.
8 lumens:
9 type: integer
10 minimum: 0
11 description: Light intensity measured in lumens.
12 sentAt:
13 type: string
14 format: date-time
15 description: Date and time when the message was sent.
The Payload
property defines the content of the event using AsyncAPI schemas. It means that your event payload should contain an id
and a lumens
property —which are integers bigger than zero—, and a sentAt
property that should be a string containing a date and time.
JSON Schema Draft 07 is 100% compatible with AsyncAPI schemas.
Cool! You're done with your AsyncAPI file! Now let's get into generating code.
Generating code
In this step, we will generate your code, you'll use the AsyncAPI Generator Node.js template.
1. Install the generator to use it as a command-line tool
1npm install -g @asyncapi/generator
2. Create a directory for your projects and enter it:
1mkdir streetlights && cd "$_"
3. Create a file with the AsyncAPI machine-readable description you defined before using terminal. The cat
command is a utility command in Linux. On Windows use type
instead of cat
:
1cat <<EOT >> asyncapi.yaml
2asyncapi: '2.5.0'
3info:
4 title: Streetlights API
5 version: '1.0.0'
6 description: |
7 The Smartylighting Streetlights API allows you
8 to remotely manage the city lights.
9 license:
10 name: Apache 2.0
11 url: 'https://www.apache.org/licenses/LICENSE-2.0'
12servers:
13 mosquitto:
14 url: mqtt://test.mosquitto.org
15 protocol: mqtt
16channels:
17 light/measured:
18 publish:
19 summary: Inform about environmental lighting conditions for a particular streetlight.
20 operationId: onLightMeasured
21 message:
22 name: LightMeasured
23 payload:
24 type: object
25 properties:
26 id:
27 type: integer
28 minimum: 0
29 description: Id of the streetlight.
30 lumens:
31 type: integer
32 minimum: 0
33 description: Light intensity measured in lumens.
34 sentAt:
35 type: string
36 format: date-time
37 description: Date and time when the message was sent.
38EOT
4. Trigger generation of the Node.js code:
1ag asyncapi.yaml @asyncapi/nodejs-template -o output -p server=mosquitto
5. And voilà! List all files in directory and check that Node.js application is generated:
1cd output && ls
Running your code
1. Install dependencies of newly generated application:
1npm install
2. Start the application:
1npm start
3. In another terminal install the MQTT.js library:
1npm install mqtt -g
4. Send a correct message to your application:
1mqtt pub -t 'light/measured' -h 'test.mosquitto.org' -m '{"id": 1, "lumens": 3, "sentAt": "2017-06-07T12:34:32.000Z"}'
5. Send an incorrect message to your application:
1mqtt pub -t 'light/measured' -h 'test.mosquitto.org' -m '{"id": 1, "lumens": "3", "sentAt": "2017-06-07T12:34:32.000Z"}'
6. Go back to the previous terminal and check if your application logged the streetlight condition you just sent, with errors related to the invalid message.
Summary
In this tutorial, we learned how to create an AsyncAPI description file and how to generate our API code from the AsyncAPI Generator, by using Node.js and Mosquitto as the message broker. We also learned how to implement the event-driven architecture in a real-life example, using pub/sub architecture to send a message to our application with an MQTT and Mosquitto message broker.
Today's sample code is only a bootstrap; you'll need to add your own business logic into it. Take some time to play with it. There are still lots of things to be covered, but the intent of this tutorial is to make it simple for you to get an idea of the potential.
We would love to see what you create with AsyncAPI! As an open-source project, we're open to proposals, questions, suggestions, and contributions. If you don't feel in the mood to contribute but you're using AsyncAPI, just raise your hand by creating an issue in our Github repo or join our Slack channel. Don't be shy.