AsyncAPI: 2020’s Industry Standard For Messaging APIs?


The industry is made up of a wide variety of implementations, solutions, and frameworks. Within this cloud of competing systems, the messaging API fights for a very specific, often niche section of development efforts. The quest to find a strong standard for these types of APIs, then, is a continuing effort.

One answer to the question of a standardized definition specification for such APIs is AsyncAPI. AsyncAPI is specifically designed to offer extensible, powerful, and transformable definitions for messaging APIs — but is it a good solution in practice? And more to the point, why is a standard even necessary?

This post follows a presentation by Francisco Méndez of AsyncAPI. Watch here:

The Need for an Industry Standard

“We as an industry, we need a common language. Imagine if we didn’t have things like HTTP. Could you imagine the web today without HTTP? That would be a mess, That would be an insane mess, the browser having to implement different kinds of protocols. […] One of the main purposes of AsyncAPI was to make it machine-readable. You can have human-readable documentation, which might be very nice and beautiful, and it might explain things in a nice way, but that cannot be parsed by a machine, that cannot be shared with another person in the world that doesn’t speak the same language. So, we need something that can be exchanged.”

Before we dive into AsyncAPI specifically, we should lay the groundwork on which exists. The reason AsyncAPI is so important comes down to the need for a common language. In its most basic form, language defines how we communicate. This is true in terms of our spoken languages, but the same remains true when we discuss the “language” of technical strategies, specifications, frameworks, and modes of communication.

Choosing to use different approaches that are mismatched, or sometimes completely incompatible, can result in a massive amount of confusion that can be more damaging than any other constraint the average project might come up against. This is largely the argument behind standardization in the tech space – that using standard approaches delivers better benefits over a longer period of time with fewer headaches. We can isolate some of these benefits to demonstrate the value of such a standardization approach.

Benefits of Standardization

First, adopting standards can result in the generation of more effective standardized tools. When you use different approaches, this value is lost – having differences between API approaches and methodologies results in proprietary tools and the issues that arise when attempting to join those tools together in a common approach.

Second, there is an argument that can be made from a pure cost-benefit position. The cost of moving from approach to approach and adapting to a new methodology rather than utilizing a proven, standard solution can be quite expensive. This cost is not only in terms of economic value but in terms of hours and the amount of knowledge investment that comes with creating such an environment and application.

While there is a bevy of additional issues that can be raised, perhaps the strongest argument against proprietary approaches is the difficulty in integration and cooperation. Failing to have a common methodology means that you have worse integration between disparate groups in your internal organization, less effective cooperative efforts with differing partners external to the integration, and, ultimately, difficulty in communication at every level.

For all of these reasons, adopting a standard is something that should be viewed as what it is – a net benefit for the organization. This is not to say that other innovations should be ignored or that the industry should just choose a standard to the exclusion of everything else – all it means is that the industry should choose a general approach for specific applications if it wants to mature and reap the benefits of standardization.

Machine vs. Human Readability

There is a caveat here, though – even if we do agree on a framework or a language, in essence, there is also an underlying issue in terms of the method of delivery. There are fundamentally two modes or methods of communication: machine-readable and human-readable. Even if the entire tech world determined that they were going to use Language #1, the documentation around these efforts, the way they spoke to one another, the way solutions were designed around them, and the fundamental method by which they were understood would be just as important, and would largely be separated into one of these two camps.

Machine readability is essentially a mode of communication which priorities function over form. Machine-readable languages prioritize the organization of data into a format that is readable and transformable by machines, with the expectation that machines will be interacting and reacting with data of its own in a machine-readable format.

While this data is difficult for end-users to understand or utilize, this is an artifact of its design – the code isn’t meant for human users, its meant for machines. This often results in a more concise code with less bloat (though, like most benefits discussed herein regarding readability, this is not assured). An example of this type of data would be JSON, which is often quite complex if not highly verbose and detailed.

Human readability, on the other hand, is code that is specifically designed to prioritize human interaction and understandability. In this case, the code is designed for humans, and as such, it typically (although, again, not always) has greater bloat in the form of data clarification and context. An example of this type of data would be YAML, which has much more clarity in a human-readable structure.

It should be noted that the elements of the readability discussed above are not always constant. In theory, a machine-readable format rids itself of the formatting that a human-readable language has. In reality, some human-readable languages are more concise than other machine-readable languages. The tradeoffs in size, efficiency, etc. are not always assured, but generally speaking, ensuring compatibility with both methods is much more effective than choosing a singular approach.

What is AsyncAPI?

AsyncAPI is a specification that is specifically designed to describe event-driven microservices. For all of the reasons stated previously, a standardized format has been required by many developers – AsyncAPI, then, is the proposed answer to that for almost anything that depends on a message-driven architecture.

With all of this said, a standard is only as good as those who accept it. To that end, AsyncAPI has several large names backing its use and implementation. AsyncAPI is used by industry giants such as Salesforce, MuleSoft, Slack, and Tibco to great effect to drive documentation for their message-based systems.

With this in mind, what does AsyncAPI specifically do to solve the standards-demanding problems? And why do so many big names utilize AsyncAPI as part of their solution?

AsyncAPI is a Contract Mechanism

“All of you have felt the pain of not having a contract for all your messages in your system. You know that we have RAML, we have OpenAPI, we have many specification languages for our API contracts, but we often forget about the messaging API’s contract. This is especially important because we tend to push messages into a system broker.”

AsyncAPI functions on two assumptions – that messages drive most API interactions at their core, and that these messages are either actions or events. In essence, AsyncAPI believes that everything can be represented as a message system, with a header and payload as both optional and non-required. In this view of API communication, AsyncAPI seeks to enable the definition of APIs using protocol-agnostic channel-based definitions.

By defining a very specific, contractual relationship between elements in the API, developers can more accurately control and manage the flow of these messages and their resultant output. Since these messages are usually pushed into a broker, having a commonly defined and accepted contract allows for a much higher, granular system of control, ultimately resulting in a more understandable, effective, and efficient system overall.

AsyncAPI is Protocol Agnostic

“[AsyncAPI does not] enforce any particular protocol, but we do offer mechanisms to define which one your API uses. That’s due to the many different approaches in the messaging world on how things work.”

By shifting the focus of the interactions on the API away from component to component, and instead representing it as a simple message-based system, AsyncAPI is allowed to describe APIs in a more removed sort of manner. These descriptions are either in JSON or YAML, and describe the fundamental message structure, rather than the component interactions – accordingly, AsyncAPI is protocol agnostic.

Protocol agnosticism is a very important element for this type of solution due to the very nature of the message-based approach. Many solutions exist that offer the same sort of documentation methodologies across a variety of APIs, but these are often locked into a proprietary language or format. While this isn’t a problem when the codebase already adheres to these rules, it is a constraint that is more a roadblock than it is a benefit.

By remaining protocol agnostic, AsyncAPI can prevent a unified standard without having to develop a wide variety of integrations and porting systems – it should largely work out of the box.

AsyncAPI is Extensible

Though not as high-profile as other elements herein, the fact that AsyncAPI is open source is very important to the success of such a standard. By being open-source, AsyncAPI has two serious benefits that just wouldn’t be possible in a closed source system.

Firstly, an open-source AsyncAPI is auditable. The code can be tested, reviewed, and revised, meaning that any concerns as to how the system works can be identified and fixed with relative ease and at a lower average cost.

Second, being open source means that AsyncAPI offers a standard platform from which to build upon. If a provider finds AsyncAPI does almost everything, it wants it to do, but not quite, the result is different between closed and open-source implementations – in a closed source, the provider has to hope for a business-to-business custom integration or just accept they are out of luck; in an open-source environment, the core system can be customized and changed, as long as the licenses are matched, to be precisely what the provider needs.

AsyncAPI is Designed for Ultimate Readability

Earlier, the differences (and importances) of readability models were discussed at length. Machine readability delivers excellent portability and extensibility. Human readability allows for easier real-time use and integration. Adopting one over the other is a matter of need and appropriateness – with AsyncAPI; however, this choice doesn’t need to be made, as AsyncAPI is designed to support both. APIs can be described using either JSON or YAML, and GUIs can be integrated with the AsyncAPI experience for ultimate usability.

Having both options for the provider not only makes business sense, it makes design sense – the ultimate choice is going to be made by the person requesting the data, and allowing them to make that choice independently without limitations will result in a better experience.

What AsyncAPI Looks Like

While we’ve discussed the top-level implementation of AsyncAPI, it does also help to include some actual code for what AsyncAPI looks like as a sort of barometer for providers looking for a new solution. To that end, the following is provided as a rough guide to how AsyncAPI works, and what it looks like. This content is largely borrowed from the first piece on this subject at Nordic APIs, Tooling Review: AsyncAPI.

AsyncAPI is primarily concerned with contractual representations of the API messaging system. Accordingly, the first thing it does is define an info object. The info object is the principal method by which the API states its title, description, etc. The info object statement looks as follows:

{
  "asyncapi": "2.0.0",
  "info": {
    "title": "AsyncAPI Sample App",
    "description": "This is a sample server.",
    "termsOfService": "https://asyncapi.org/terms/",
    "contact": {
      "name": "API Support",
      "url": "https://www.asyncapi.org/support",
      "email": "support@asyncapi.org"
    },
    "license": {
      "name": "Apache 2.0",
      "url": "https://www.apache.org/licenses/LICENSE-2.0.html"
    },
    "version": "1.0.1"
  }

The next step in this process is the creation of the Servers object. This object defines the server URLs, and is the principal definition and routing method used to handle the API messages. It looks as follows:

"servers": {
    "development": {
      "url": "development.gigantic-server.com",
      "description": "Development server",
      "protocol": "mqtt"
    },
    "staging": {
      "url": "staging.gigantic-server.com",
      "description": "Staging server",
      "protocol": "secure-mqtt"
    },
    "production": {
      "url": "api.gigantic-server.com",
      "description": "Production server",
      "protocol": "secure-mqtt"
    }
  }

Once we have defined our Servers object, we need to establish the Channels element. In AsyncAPI parlance, the channel is the top-level definition by which all messages are defined – they can be roughly considered analogous to HTTP API URL paths, and this definition is used to govern the transfer of messages according to purpose and content. This definition looks as follows:

"channels": {
    "user/signedup": {
      "subscribe": {
        "message": {
          "$ref": "#/components/messages/userSignedUp"
        }
      }
    }
  }

Now that we have the groundwork laid, we can define the Components. Components are reusable objects whose sole purpose is to define and limit messages – this is the chief controlling mechanism employed by AsyncAPI. It looks as follows:

"components": {
    "schemas": {
      "email": {
        "type": "string",
        "format": "email"
      },
      "sentAt": {
        "type": "string",
        "format": "datetime"
      },
      "address": {
        "type": "object",
        "properties": {
          "street": {
            "type": "string"
          },
          "postalCode": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "country": {
            "type": "string"
          }
        }
      }
    },
    "messages": {
      "userSignedUp": {
        "summary": "Action to sign a user up.",
        "description": "Multiline description of what this action does.\nHere you have another line.\n",
        "tags": [
          {
            "name": "user"
          },
          {
            "name": "signup"
          }
        ],
        "bindings": {
          "mqtt": {
            "cleanSession": false,
            "clientId": "myApp"
          }
        },
        "headers": {
          "type": "object",
          "properties": {
            "myAppHeader": {
              "type": "string"
            }
          }
        },
        "payload": {
          "type": "object",
          "properties": {
            "username": {
              "type": "string"
            },
            "email": {
              "$ref": "#/components/schemas/email"
            },
            "address": {
              "$ref": "#/components/schemas/address"
            },
            "sentAt": {
              "$ref": "#/components/schemas/sentAt"
            }
          }
        }
      }
    }
  }
}

Conclusion

AsyncAPI is not a magic bullet – there will always be competing standards and additional, case-specific solutions. That being said, AsyncAPI is very powerful at what it does and is a very good solution for any message-driven use case. With large names in the industry directly supporting it, it’s hard to argue against the implementation on the basis of usability – in addition, its extensibility is world-class, with its open-source codebase offering excellent opportunities for custom solutions in addition to standardized methodologies.

What do you think about AsyncAPI and its quest to become an industry standard? Let us know below!