AsyncAPI 3.0.0 Release Notes

Jonas Lagoni

Jonas Lagoni

·10 min read

The new version of the AsyncAPI specification - 3.0.0 - is now available and is packed with goodies! Some clear up confusion, some add features, and others improve maintainability.

To make the information as clear as possible, we have split up the information into digestible chunks.

If you want to get an overview of:

Overview

This post will give you an overview of all the changes done in v3.

Operation, channel, and message decoupling

In v2, it has never been possible to re-use channels, because it was directly coupled with operations of an application.

In v3, this is now possible, with the mindset that a channel and message should be detached from the operations performed. This means for any message broker, for example, for Kafka, channels now ONLY define topics and the messages it contains. For REST interfaces, it's all the paths and corresponding messages across all request types. For WebSocket, it's all the messages flowing through the WebSocket server. For Socket.Io, it defines all the rooms and messages therein.

This change makes the channels reusable across multiple AsyncAPI documents.

1asyncapi: 3.0.0
2...
3channels:
4  UserSignup:
5    address: user/signedup
6    messages: 
7      UserMessage: 
8        payload:
9          type: object
10          properties:
11            displayName:
12              type: string
13              description: Name of the user
14operations:
15  ConsumeUserSignups:
16    action: receive
17    channel: 
18      $ref: "#/channels/UserSignup"

Messages instead of message

As you probably noticed above, messages in channels are no longer singular, and with oneOf, instead, messages are defined as key/value pairs in the Messages Object. This was part of the request-reply feature to enable easier referencing of messages.

1asyncapi: 3.0.0
2...
3channels:
4  UserSignup:
5    address: user/signedup
6    messages: 
7      UserMessage: 
8        ...
Issue(s)PR(s)Migration Guide
#94#827Messages instead of message

Publish and subscribe confusion

In v2, the publish and subscribe operation keywords have always been confusing. Does it mean my application is published to the channel? Does it mean you publish for me? Who are you in this context?

In v3, we try to clear this up. You only need to worry about your application's behavior. No more confusion about what and who does what. We achieve this through two new Operation Object keywords, send and receive, i.e. your application either sends or receives something.

This description, of course, alters slightly based on protocol; for the generic message brokers, you produce or consume messages, but in the abstract AsyncAPI perspective, you still send or receive messages.

1asyncapi: 3.0.0
2...
3operations: 
4  SendUserSignedUp:
5    action: send
6  ReceiveUserSignedUp:
7    action: receive
Issue(s)PR(s)Migration Guide
#829#847Operation keywords

Request/Reply

One of the longest requested features is request and reply... and it's finally here!

One thorn in the eye of this feature has always been the publish and subscribe confusion, which complicated any efforts to achieve a workable solution. However, we now have a solution with that out of the way. 🔥

This feature has been designed with the following use cases in mind:

  • Broker-based messaging with well-defined response topic + "correlationId".
  • Broker-based messaging with per process individual inbox aka "replyTopic" + "correlationId".
  • Broker-based messaging with a temporary reply topic for an individual response.
  • WebSocket, which has no topics, where the channel is a TCP connection where messages flow.
1...
2action: send | receive
3reply:
4  address:
5    location: '$message.header#/replyTo'
6  channel:
7    $ref: '#/channels/userSignupReply'
8  messages:
9    - $ref: '#/components/messages/userSignedUpReply'

Read more about the Operation Reply Object here.

Issue(s)PR(s)
#94, #558#847

Optional channels

We have seen many use cases where an AsyncAPI document has been used as a form of menu or collection of definitions. To do this in v2 would require a bit of a hack. But in v3, channels are now entirely optional. This means that it's now possible to have a valid AsyncAPI document as such:

1asyncapi: 3.0.0
2...
3components:
4  ...
Issue(s)PR(s)
#829#847

Unified referencing behaviors

In v2, there were two instances where we used implicit references; server security configuration, by name referencing security requirement object in components, for channels to reference global servers by name. To stay as consistent as possible, we wanted to unify how references were used, which means that in v3, we ONLY use explicit references.

The scopes information in the Security Schema Object is also now an array instead of an object.

1asyncapi: 3.0.0
2...
3servers: 
4  SomeServer:
5    security:
6      - $ref: '#/components/securitySchemes/SomeSecurity'
7channels:
8  SomeChannel: 
9    servers: 
10      - $ref: '#/servers/SomeServer'
11components:
12  securitySchemes:
13    SomeSecurity:
14      ...
15      scopes: [...]

Common metadata fields

There has been some inconsistency between which metadata fields are available in the different objects. Now we have added a few extra fields:

1asyncapi: 3.0.0
2...
3servers:
4  SomeServer:
5    title: Some Server title
6    summary: This some server is for something
7    externalDocs:
8      ...
9channels:
10  SomeChannel:
11    title: Some channel title
12    summary: Some channel summary
13operations:
14  SomeOperation:
15    title: Some operation title
16    traits:
17      - title: Some operation traits title
Issue(s)PR(s)
#795#796

Cleaning up the root object

There was two meta information lingering in the root of the AsyncAPI object, which did not make much sense since we have the info object for all the meta information.

Therefore the root tags and externalDocs have been moved to the Info Object.

1asyncapi: 3.0.0
2...
3info:
4  ...
5  externalDocs:
6    description: Find more info here
7    url: https://www.asyncapi.org
8  tags:
9    - name: e-commerce
10...
PR(s)Migration Guide
#794Moved metadata

Splitting out server URL into host and pathname

There has been some confusion about what the url of a server should contain; is it both protocol + host + path? What about the protocol field, then? Therefore each field now has its field for the host, path, and protocol in the Server Object.

1asyncapi: 3.0.0
2...
3servers:
4  localhost:
5    host: localhost
6    path: /api/v1,
7    protocol: mqtt
Issue(s)PR(s)Migration Guide
#547, #274#888Server URL splitting up

More reusable objects in components

This is a bit of a mixture between some of the features, that all added a little to this. It's now possible to add more stuff under the Components Object:

  • Replies
  • Reply addresses
  • Tags
  • External docs
  • Operations
  • Channels
1asyncapi: 3.0.0
2...
3components:
4  ...
5  replies:
6    ...
7  replyAddresses:
8    ...
9  tags: 
10    ...
11  externalDocs:
12    ...
13  operations:
14    ...
15  channels:
16    ...
Issue(s)PR(s)
#829#847, #792, #806, #827

New trait behavior

Traits in v2 always replaced any duplicate properties that were defined both in traits and the associated object. This meant, for example, if the message traits defined headers and the message object did as well, only the message trait headers would be applied because it overwrote anything you wrote in the message object.

In v3, this has now been changed so that a property on a trait MUST NOT override the same property on the target object.

For example, take a look at this message:

1messageId: userSignup
2description: A longer description.
3payload:
4  $ref: '#/components/schemas/userSignupPayload'
5traits:
6  - name: UserSignup
7    title: User signup
8    summary: Action to sign a user up.
9    description: Description from trait.

Take notice of how description is not overwritten by the traits:

1messageId: userSignup
2name: UserSignup
3title: User signup
4summary: Action to sign a user up.
5description: A longer description. # it's still description from "main" object
6payload:
7  $ref: '#/components/schemas/userSignupPayload'
Issue(s)PR(s)Migration Guide
#505#517, #532, #907New trait behavior

Schema format and payload definition

With schemas, one thing that has always been impossible was reusing schemas with different schema formats. That's because the schema format information is part of the message object. That means that if you reference a Schema object, it has no information about the schema format because it's not located together.

In v3, schemaFormat has been removed from the Message Object and Message Trait Object, and a new schema Object called Multi Format Schema Object has been introduced, which pairs a schema together with its schema format. Which now enables much better reusability:

1asyncapi: 3.0.0
2...
3components:
4  schemas:
5    avroSchema:
6      schemaFormat: 'application/vnd.apache.avro+yaml;version=1.9.0'
7      schema:           
8        type: record
9        name: User
10        namespace: com.company
11        doc: User information
12        fields:
13          - name: displayName
14            type: string
Issue(s)PR(s)Migration Guide
#622#797, #910Schema format and schemas

Simplified Parameters

In v2, it was possible to use the full power of JSON Schema to define parameters, however, it introduced a lot of complexity to parameters, so for v3 it was dialed way down to only allow a very small set of properties.

In v3, the new Parameter object can now only have the following properties: enum, default, description, examples, and location.

1asyncapi: 3.0.0
2...
3channels: 
4  userSignup:
5    address: user/{userId}/signedup
6    parameters:
7      userId:
8        description: Id of the user.

By default this means that any parameter is of type string.

Issue(s)PR(s)Migration Guide
#583#935Restricted parameters object

Editorial Changes

We have removed the note that stated we strived to be compatible with OpenAPI where possible because, with the recent changes, this is no longer the case. That said, we still strive to make the different specs as interoperable as possible i.e., with Avro, RAML, OpenAPI Schema, etc.

Acknowledgements

Spec 3.0 have been a massive undertaking, so I would like to say a huge "thank you!" to everyone who has been involved; maybe you commented on your views, added to discussions, joined the live meetings, championed changes, or reviewed proposed changes; this section is for you!

Thank you, Simon Heimler, Vladimír Gorej, Fran Méndez, Lukasz Gornicki, Sergio Moya, Michael Davis, Maciej Urbańczyk, Jesse Menning, Heiko Henning, Gerald Loeffler , c-pius, Ian Cooper, Dale Lane, Jörg Walter, Nic Townsend, Laurent Broudoux, olamiral, Iván García Sainz-Aja, Fabian Bühler, John Fallows, Adrian Hope-Bailie, Christian (prdatur), Karl Morrison, Javier Jiménez Roda, Marek Sebera, Nathanaël Lécaudé, Jeremy Whitlock, souvik, Animesh Kumar, Samir AMZANI, Alejandra Quetzalli, Vaishnavi, Mahfuza, Bhaswati, Cynthia Peter, Arya Gupta, Joy Almeida, Hridyesh, Rohit, Ashish Padhy, Al Amin Muhammad, nickshoe, Khuda Dad Nomani, V Thulisile Sibanda, Ace, Mihael Bosnjak, Sambhav Gupta, Jonas Lagoni, Afzal Ansari