//

AsyncAPI specification updates

23.2.2022 | 6 minutes of reading time

Almost six months have passed since my introductory post about AsyncAPI , which is already an eternity in our fast-moving IT world. 😉 Shortly after publishing said post, more precisely in September last year, version 2.2.0 of the specification was released. At the beginning of February this year there was another so-called minor release to AsyncAPI version 2.3.0. Both versions are backward compatible with regard to the written API description, so that an update of the existing version value for the key asyncapi shouldn’t be a problem and the description is still valid afterwards.
I would also like to use the previously used description again, which has been optimized a bit in the meantime, and use it to perform the migrations to version 2.3.0 of the specification.

1asyncapi: '2.1.0'
2info:
3  title: Order Service
4  version: 1.0.0
5  description: The service is in charge of processing orders
6  contact:
7    name: Daniel Kocot
8    email: daniel.kocot@codecentric.de
9  license:
10    name: Apache 2.0
11    url: https://www.apache.org/licenses/LICENSE-2.0.html
12servers:
13  rabbitmqInStaging:
14    url: rabbitmq-staging.codecentric.de:{port}
15    description: RabbitMQ Broker in staging environment
16    protocol: amqp
17    protocolVersion: '0.9.1'
18    variables:
19      port:
20        default: '5672'
21        enum:
22          - '5672'
23          - '15672'
24  rabbitmqInProd:
25    url: rabbitmq.codecentric.de:{port}
26    description: RabbitMQ Broker in production environment
27    protocol: amqp
28    protocolVersion: '0.9.1'
29    variables:
30      port:
31        default: '5672'
32        enum:
33          - '5672'
34          - '15672'
35channels:
36  orderProcessed:
37    publish:
38      operationId: orderProcessedPub
39      description: Payload of processed order
40      message:
41        $ref: '#/components/messages/orderProcessed'
42      bindings:
43        $ref: '#/components/messageBindings/amqp/bindings'
44    subscribe:
45      operationId: orderProcessedSub
46      description: Payload of processed order
47      message:
48        $ref: '#/components/messages/orderProcessed'
49      bindings:
50        $ref: '#/components/messageBindings/amqp/bindings'
51    bindings:
52      amqp:
53        $ref: '#/components/channelBindings/amqp'
54components:
55  schemas:
56    OrderPayload:
57      type: object
58      properties:
59        id:
60          type: integer
61          format: int64
62          description: ID of received order
63        customerReference:
64          type: string
65          description: Reference for the customer according the order
66  messages:
67    orderProcessed:
68      name: orderProcessed
69      title: Order Processed
70      summary: Inform about a new processed order in the system
71      contentType: application/json
72      payload:
73        $ref: '#/components/schemas/OrderPayload'
74  channelBindings:
75    amqp:
76        is: routingKey
77        exchange:
78          name: orderExchange
79          type: direct
80          durable: true
81          vhost: /
82        bindingVersion: 0.2.0
83  messageBindings:
84    amqp:
85      bindings:
86        amqp:
87          timestamp: true
88          ack: false
89          bindingVersion: 0.2.0
90

Assigning channels to servers

Let’s start directly with the first feature, the assignment of channels to servers, which has been available since AsyncAPI 2.2.0. This enables us to assign the respective channel to one or more specific servers. This is done by setting the optional servers property of type string related to the Channel Item object. Please note that the names of the servers always need to be the same as the names of the servers defined in the server object. We now adapt the above example to the feature accordingly.

1asyncapi: '2.2.0'
2info:
3  title: Order Service
4  version: 1.0.0
5  description: The service is in charge of processing orders
6  contact:
7    name: Daniel Kocot
8    email: daniel.kocot@codecentric.de
9  license:
10    name: Apache 2.0
11    url: https://www.apache.org/licenses/LICENSE-2.0.html
12servers:
13  rabbitmqInStaging:
14    url: rabbitmq-staging.codecentric.de:{port}
15    description: RabbitMQ Broker in staging environment
16    protocol: amqp
17    protocolVersion: '0.9.1'
18    variables:
19      port:
20        default: '5672'
21        enum:
22          - '5672'
23          - '15672'
24  rabbitmqInProd:
25    url: rabbitmq.codecentric.de:{port}
26    description: RabbitMQ Broker in production environment
27    protocol: amqp
28    protocolVersion: '0.9.1'
29    variables:
30      port:
31        default: '5672'
32        enum:
33          - '5672'
34          - '15672'
35channels:
36  orderProcessed:
37    servers:
38      - rabbitmqInStaging
39    publish:
40      operationId: orderProcessedPub
41      description: Payload of processed order
42      message:
43        $ref: '#/components/messages/orderProcessed'
44      bindings:
45        $ref: '#/components/messageBindings/amqp/bindings'
46    subscribe:
47      operationId: orderProcessedSub
48      description: Payload of processed order
49      message:
50        $ref: '#/components/messages/orderProcessed'
51      bindings:
52        $ref: '#/components/messageBindings/amqp/bindings'
53    bindings:
54      amqp:
55        $ref: '#/components/channelBindings/amqp'
56components:
57  schemas:
58    OrderPayload:
59      type: object
60      properties:
61        id:
62          type: integer
63          format: int64
64          description: ID of received order
65        customerReference:
66          type: string
67          description: Reference for the customer according the order
68  messages:
69    orderProcessed:
70      name: orderProcessed
71      title: Order Processed
72      summary: Inform about a new processed order in the system
73      contentType: application/json
74      payload:
75        $ref: '#/components/schemas/OrderPayload'
76  channelBindings:
77    amqp:
78        is: routingKey
79        exchange:
80          name: orderExchange
81          type: direct
82          durable: true
83          vhost: /
84        bindingVersion: 0.2.0
85  messageBindings:
86    amqp:
87      bindings:
88        amqp:
89          timestamp: true
90          ack: false
91          bindingVersion: 0.2.0
92

Servers and channels as reusable objects

With version 2.3.0 servers and channels are available as reusable objects. Thus, the two elements only have to be defined within the components, then they can be referenced within the description. This is now also applied to our example description.

1asyncapi: '2.3.0'
2info:
3  title: Order Service
4  version: 1.0.0
5  description: The service is in charge of processing orders
6  contact:
7    name: Daniel Kocot
8    email: daniel.kocot@codecentric.de
9  license:
10    name: Apache 2.0
11    url: https://www.apache.org/licenses/LICENSE-2.0.html
12servers:
13  staging:
14    $ref: '#/components/servers/rabbitmqInStaging'
15  production: 
16    $ref: '#/components/servers/rabbitmqInProd'
17channels:
18  orderProcessed:
19    servers:
20      - staging
21    publish:
22      operationId: orderProcessedPub
23      description: Payload of processed order
24      message:
25        $ref: '#/components/messages/orderProcessed'
26      bindings:
27        $ref: '#/components/messageBindings/amqp/bindings'
28    subscribe:
29      operationId: orderProcessedSub
30      description: Payload of processed order
31      message:
32        $ref: '#/components/messages/orderProcessed'
33      bindings:
34        $ref: '#/components/messageBindings/amqp/bindings'
35    bindings:
36      amqp:
37        $ref: '#/components/channelBindings/amqp'
38components:
39  schemas:
40    OrderPayload:
41      type: object
42      properties:
43        id:
44          type: integer
45          format: int64
46          description: ID of received order
47        customerReference:
48          type: string
49          description: Reference for the customer according the order
50  servers:
51    rabbitmqInStaging:
52      url: rabbitmq-staging.codecentric.de:{port}
53      description: RabbitMQ Broker in staging environment
54      protocol: amqp
55      protocolVersion: '0.9.1'
56      variables:
57        port:
58          default: '5672'
59          enum:
60            - '5672'
61            - '15672'
62    rabbitmqInProd:
63      url: rabbitmq.codecentric.de:{port}
64      description: RabbitMQ Broker in production environment
65      protocol: amqp
66      protocolVersion: '0.9.1'
67      variables:
68        port:
69          default: '5672'
70          enum:
71            - '5672'
72            - '15672'
73  messages:
74    orderProcessed:
75      name: orderProcessed
76      title: Order Processed
77      summary: Inform about a new processed order in the system
78      contentType: application/json
79      payload:
80        $ref: '#/components/schemas/OrderPayload'
81  channelBindings:
82    amqp:
83        is: routingKey
84        exchange:
85          name: orderExchange
86          type: direct
87          durable: true
88          vhost: /
89        bindingVersion: 0.2.0
90  messageBindings:
91    amqp:
92      bindings:
93        amqp:
94          timestamp: true
95          ack: false
96          bindingVersion: 0.2.0
97

Contributor time

When looking at the description, it quickly becomes apparent that there is further potential with regard to reusability. This refers specifically to the variables for the server object. Exactly this caused me to post a Request for Comments (RFC) in the Git repo for the specification. In the meantime three pull requests followed out of the RFC. One for the specification itself and the other for the JSON schema . I submitted the third and final pull request for the JS parser shortly after the post was published. Now the feature can become a part of the next release (2.4.0) of the AsyncAPI specification. Hopefully ;). If you also have a feature in mind for an open-source project, I can only encourage you to put it into action. Only in this way can we help keep open source an integral part of our daily work.

New protocol bindings

After this short trip into the world of open source contributions I would like to take a look at the innovations regarding protocol bindings. What is actually meant by protocol bindings? Protocol bindings or short bindings describe the specifics of the used protocol. They are the basis of the architecture component, which is an essential part of the description with AsyncAPI. This can be done on the levels of server, channel, operation and message. Up to version 2.1.0 the following protocols are supported:

  • HTTP
  • Websockets
  • Kafka
  • AMQP 0.91
  • AMQP 1.0
  • MQTT
  • MQTT 5
  • NATS
  • JMS
  • SNS
  • SQS
  • STOMP
  • Redis
  • Mercure
  • IBM MQ

However, the binding for IBM MQ cannot be applied at the level of ‘operation’. With the last two releases two more bindings for Anypoint MQ and Solace have been added. More detailed information about the bindings can be found at Repo within the AsyncAPI Org in GitHub.

Outlook and summary: Beyond AsyncAPI version 2.3.0

In AsyncAPI, we find a very convenient way to describe event- and message-driven architectures and also to incorporate this description into existing processes of our API lifecycle, supported by CI/CD pipelines. It will be exciting to see how this and other specifications and the topics around the description of APIs will evolve in the coming years. So look forward to more posts on these aspects.

share post

Likes

0

//

More articles in this subject area\n

Discover exciting further topics and let the codecentric world inspire you.

//

Gemeinsam bessere Projekte umsetzen

Wir helfen Deinem Unternehmen

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.