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
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
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
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.
More articles in this subject area
Discover exciting further topics and let the codecentric world inspire you.
Blog author
Daniel Kocot
Senior Solution Architect / Head of API Consulting
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.