Designing-Asynchronous-Microservices-With-AsyncAPI

In the microservices world, it’s essential to design applications carefully so they scale and function efficiently. When we build services, it’s also important to keep performance in mind so that microservices remain performant as they grow in size. And in recent years, the key to good service design lies in asynchronous communication.

Asynchronous communication is when one service sends a message to another service without waiting for a response. This allows a microservice to continue with its work instead of waiting for a response before proceeding further. Below, we’ll cover everything you need to know about designing microservices with AsyncAPI.

What is AsyncAPI?

AsyncAPI is a specification for describing and documenting asynchronous APIs. It’s designed to complement existing API specifications, such as OpenAPI (formerly known as Swagger) and RAML. AsyncAPI provides a standardized way to describe the message flows and events of an asynchronous API, as well as the format of the messages exchanged between the producers and consumers of the API. AsyncAPI is agnostic of the underlying message transport protocol and can be used to describe APIs that use message queues, webhooks, WebSockets, or any other asynchronous communication mechanism.

To explain this even further, let’s create an AsyncAPI specification and create publishers and subscribers from it.

Specifications

AsyncAPI is specifically designed for use with message-based architectures such as Pub/Sub systems, queues, and event streams. AsyncAPI specifications are written in YAML or JSON and are composed of three main sections:

  • The AsyncAPI version section is a must-have for any AsyncAPI spec. This is the specification for describing asynchronous APIs. Similar to OpenAPI, it aims to provide a standard way of describing and documenting these APIs.
  • The info section contains general information about the API. It specifies the API’s title, version, and description.
  • The channels section contains information about the API’s message channels. This includes the channel’s name, description, and message format. You will also need to specify the channel’s publish and subscribe URLs.

There are still some more components left that are not mentioned, and you can read more about them here. You can also use AsyncAPI’s Studio tool to display your specification file neatly and cleanly and also validate and render the specification as you work on it!

Tutorial

Below is the YAML specification we’ll use in this article. So, create a file called api-spec.yaml and paste the below code:

#api-spec.yaml

asyncapi: 2.0.0

info:
  title: User API
  version: '1.0.0'
  description: API to manage users

servers:
  development:
    url: localhost
    protocol: redis
    description: Development Broker Server

channels:
  user/update:
    description: Topic for user updates
    subscribe:
      operationId: receive_user_update
      message:
        $ref: '#/components/messages/UserUpdate'
    publish:
      message:
        $ref: '#/components/messages/UserUpdate'

components:
  messages:
    UserUpdate:
      name: userUpdate
      title: User Update
      summary: Inform about users updates
      payload:
        type: object
        required:
          - id
        properties:
          id:
            type: string
          name:
            type: string
          age:
            type: integer

defaultContentType: application/json

Now that we have the spec, we can do anything we want with it, as it’s a normal YAML file. But let’s use it for its intended purpose, as a subscribe and publish system.

Subscribers Module

The Subscribers module defines the message consumption endpoints for a message publisher. These endpoints are responsible for receiving messages from the message publisher and delivering them to the subscribers. We can create such a module in Python as follows:

# user_events.py

from typing import Any


async def receive_user_update(message: Any) -> None:
    print(f"Received update for user id={message.id}")

Code Explanation

This script will listen for any incoming response from the publish module, essentially working as a messaging or broadcasting system. You can run it with the following command:

PYTHONPATH=. asyncapi-subscriber \
    --url api-spec.yaml \
    --api-module user_events

Note: You will need to add PYTHONPATH to your systems path if it doesn’t work.

If it works properly, you will see something like this:

Waiting messages…

Publishing Module

The Posting Module is a tool that allows you to grab from your existing API specification. The specification provides an easy-to-use way of getting and utilizing its data, as well as several features that make it easy to keep track of changes to the API.

We can create the publishing module like this, but first, install the PyPI library for AsyncAPI:

pip install asyncapi[http,yaml,redis,subscriber,docs]

Now, create a file publish.py and paste the below code:

# publish.py

import asyncio

from asyncapi import build_api


api = build_api('api-spec.yaml')
channel_id = 'user/update'
message = api.payload(channel_id, id='fake-user', name='Fake User', age=33)


async def publish() -> None:
    await api.connect()
    await api.publish(channel_id, message)
    await api.disconnect()


asyncio.run(publish())

print(f"Published update for user={message.id}")

Code Explanation

Now, what this will do is send the “message” which we have defined in the script above to all the active subscribers’ modules.

And we are done! Now let’s test this out.

Output

To initiate this whole thing, start the user_events.py file first. After that, run the publish.py like so:

python publish.py

This should print a result like this:

Published update for user=fake-user

And now, if you check the user_events.py terminal, you should get a result like this:

Waiting messages...
Received update for user id=fake-user

Final Words

Applications have become more complex and interdependent. As a result, building applications in a way that allows for easy communication and collaboration between those applications has become more critical than ever. Building microservices can unlock a lot of potential in your software. However, implementing a microservices architecture can be time-consuming and difficult. That’s where AsyncAPI can help.

AsyncAPI is a specification for asynchronous APIs that allows developers to describe the structure and behavior of their APIs in a standardized way. This makes it easier for both developers and consumers of APIs to understand and use them. Additionally, AsyncAPI provides a number of features and tools that make it easier to develop and manage asynchronous APIs.