Why AsyncAPI Matters — Bridging the Gap in API Documentation — Part II

Mario Bittencourt
SSENSE-TECH
Published in
5 min readFeb 2, 2024
Photo by Andrew Neel on Unsplash

In our previous article, we introduced AsyncAPI and its basic concepts. We also provided a “Hello world” specification that covered the building blocks as well as a command/reply pattern.

We highlighted how AsyncAPI shares similarities with its synchronous counterpart — OpenAPI — not only in terms of constructs but also in its primary goal: generating documentation.

But, there is more to discuss about AsyncAPI. In this article, we will revisit the specification to showcase how it can address more complex needs. We will also explore its code generation capabilities, discuss potential uses, and consider limitations. This will give you a 360 view of the value AsyncAPI can offer.

Handling Complexity

While it’s true that many (micro)services may not require more than what has already been discussed, in practice, you may encounter needs that are more difficult to capture in AsyncAPI.

Multiple Environments

Most applications we develop go through diverse environments, from developer/sandbox to stage/qa and production. As a result, the channels used by our application are likely to be different in each environment.

However, the capabilities of AsyncAPI extend beyond this. You can specify variable placeholders in your specification. For example, imagine if you have a specific path that varies according to the environment being used.

In our documentation, it would look like this:

Figure 1. Having multiple environments can be captured using the servers block.

Dynamic Reply Channel

A request/reply pattern expects one channel for the sender to send the command and another for the receiver to provide a reply. But what happens if you have multiple senders and we need to have different reply channels?

Figure 2. In a Dynamic reply situation, the sender can specify where the reply will be sent.

Our receiver application is configured to have a static reply channel. Luckily AsyncAPI has you covered!

In this revised version we are informing that the reply channel will be resolved at runtime instead of specification time.

To achieve this, we specify a path and indicate that we expect to find that information as part of the header, in a field called replyTo.

Reusing Definitions

We hinted at this in the previous article when we used the $ref to indicate that a message would be defined later in the specification file.

Imagine a scenario where there are multiple messages sharing common elements. Instead of using a single $ref, we can take a different approach: identify true duplications and extract them into their elements.

Then, in the schemas section, you can define the elements.

Here, we can see that a list of purchased items is referenced in more than one message payload without the need for duplication.

Just be mindful to use this strategy when the elements are semantically the same.

Code Generation

Once you have created the specification, you may want to generate source code that represents the messages you defined.

AsyncAPI offers support for generating code in a variety of languages, including typescript, C#, Java to Go, and Rust.

asyncapi generate models typescript asyncapi.yaml

This feature allows you to effortlessly use these models with your sender/receiver code.

Validation and Governance

The AsyncAPI specification defines both mandatory and optional elements for any document you produce. To assist in the process, AsyncAPI provides a tool called AsyncAPI Studio, which helps to assess the validity of the document as you write it.

Figure 3. Validation errors are being reported in AsynAPI Studio.

Since using Studio is not mandatory, what happens if you choose a different path? In this case, you have a CLI tool at your disposal to validate the document. This tool can also be integrated into your development cycle, allowing you to check the document before committing it to your repository.

asyncapi validate asyncapi.yaml

If your company has a standard for documentation, you can define rules using Spectral to help you validate if the provided specification adheres to those rules.

For a more detailed discussion on governance, you can refer to our previously published article on API definitions.

Figure 4. Updated CI/CD with a validation step ensures the generated documentation will adhere to the company’s rules.

Challenges

Given everything we’ve seen so far, one might assume that AsyncAPI has a solution for all challenges, making it suitable for widespread adoption.

However, let’s take a closer look at some potential challenges we may face:

  • Definition Reusability Between Senders and Receivers

With the AsyncAPI specification, senders can define which messages they produce and make available. Any potential consumers can refer to that and have access to the evolving catalog of messages. On the other hand, receivers can also add the specification indicating which messages they consume. However, doing so means having to repeat the definition of all messages that they intend to receive.

Figure 5. Two specs where message definitions are duplicated.

While it is possible to address this issue with external reference support, it only works at a local level, meaning that both specifications would have to be maintained at the same location or repository.

Figure 6. The message definitions are stored in a separate file referenced from both (or more) spec files.
  • No WYSIWYG Authoring Tool

Although there are tools, like stoplight.io, that offer visual aids for authoring the specification, eliminating the need to memorize syntax, options, and building blocks, there is no dedicated WYSIWYG tool specifically for AsyncAPI.

  • Limited Bindings

AsynAPI supports various types of channels and their bindings, allowing you to define channel-specific settings that are relevant to you.

Unfortunately, if your choice is not among the supported options, you won’t be able to expose those details as part of the specification.

While none of the aforementioned issues are deal breakers, it’s important to consider them and manage expectations accordingly.

Conclusion

AsyncAPI has much to offer, and this series has only scratched the surface of what can be achieved. As you plan to start using AsyncAPI, it is important to understand its more advanced features, such as allowing dynamic reply channels and reusing truly common definitions among messages and applications.

It should also be noted that, like OpenAPI and others, it is not immune to limitations and some problems that are yet to be solved.

One interesting aspect worth investigating is using your CI/CD pipeline with a schema registry and connecting it to your messaging infrastructure. This approach facilitates the reusability of message definitions and runtime validation of messages, regardless of senders and receivers.

Until next time!

Editorial reviews by Catherine Heim & Gregory Belhumeur.

Want to work with us? Click here to see all open positions at SSENSE!

--

--