Implement Request/Reply in an AsyncAPI document for a Slack app

Found an error? Have a suggestion?Edit this page on GitHub

Introduction

In the Create an AsyncAPI Document for a Slackbot with WebSockets tutorial, you learned how to write an AsyncAPI document for a Slackbot Heart-Counter that actively monitored reactions associated with a message. In this lesson, let's go a step further. After receiving a reaction, Heart-Counter responds via a message back to the Slack server through WebSocket to confirm the event reception.

The interaction where the Slackbot acknowledges the event and replies with a specific response sets the stage for the Request/Reply messaging pattern discussed in this context.

Refer to the Request/Reply pattern tutorial for an introduction to its implementation.

Background context

The Request-Reply Messaging Pattern in AsyncAPI is an exciting and highly anticipated feature. The messaging pattern mirrors a traditional conversation, where one "requester" entity initiates a query or request, and the "responder" entity provides a specific and expected response. The messaging pattern can work in both synchronous and asynchronous environments and is very beneficial to decouple components by allowing them to operate independently in a distributed system.

Define messages

In the Heart-Counter tutorial, you dealt with the hello event triggered when the WebSocket connection was established and the reaction event expected when a new reaction-added event was triggered.

In this tutorial, you'll add the acknowledge message to your AsyncAPI document to represent the acknowledgment sent by the Slack application back to the server to indicate that it has successfully received the message.

1components:
2  messages:
3    reaction:
4      summary: Action triggered when the channel receives a new reaction-added event
5      payload:
6        $ref: '#/components/schemas/reaction'
7    hello:
8      summary: Action triggered when a successful WebSocket connection is established
9      payload:
10        $ref: '#/components/schemas/hello'
11    acknowledge:
12      summary: Acknowledgement response sent to Server
13      payload:
14        $ref: '#/components/schemas/acknowledge' 

Define schemas

Previously, the reaction schema was simplified to include the event payload. However, in this instance, you will be able to elaborate on the schema for the complete request it is expected to receive.

Remember

The sample request and response payloads are extracted from Slack's official documentation.

1  schemas:
2    hello:
3      type: object
4      properties:
5        type:
6          type: string
7          description: A hello string confirming WebSocket connection
8        connection_info:
9          type: object
10          properties:
11            app_id:
12              type: string
13        num_connections:
14          type: integer
15        debug_info:
16          type: object
17          properties:
18            host:
19              type: string
20            started:
21              type: string
22            build_number:
23              type: integer
24            approximate_connection_time:
25              type: integer
26    reaction:
27      type: object
28      properties:
29        envelope_id:
30          type: string
31          description: 'Unique ID assigned to payload'
32        payload:
33          type: object
34          description: 'Payload of the reaction added event'
35          properties:
36            token:
37              type: string
38            team_id:
39              type: string
40            event:
41              type: object
42              properties:
43                user:
44                  type: string
45                  description: User ID who performed this event
46                reaction:
47                  type: string
48                  description: The only reaction that you need is a heart emoji
49                item_user:
50                  type: string
51                  description: |
52                    User ID that created the original item that has been reacted
53                    to
54                item:
55                  type: object
56                  properties:
57                    channel:
58                      type: string
59                      description: Channel information of original message
60                    ts:
61                      type: string
62                      description: Timestamp information of original message
63                event_ts:
64                  type: string
65                  description: Reaction timestamp
66        type:
67          type: string
68        accepts_response_payload:
69          type: boolean 

Additionally, you will also be adding the acknowledge schema that makes use of the envelope_id attribute to send a reply back to Slack acknowledging that event has been received.

1    acknowledge:
2      type: object
3      properties:
4        envelope_id:
5          type: string
6          description: 'Unique ID of acknowledged payload'
7        payload:
8          type: object
9          description: 'Optional payload of event' 

Define acknowledge message to channel

Extend the channel the Heart-Counter used to include the acknowledge message.

1channels:
2  root:
3    address: /
4    messages:
5      hello:
6        $ref: '#/components/messages/hello'
7      reaction:
8        $ref: '#/components/messages/reaction'
9      acknowledge:
10        $ref: '#/components/messages/acknowledge' 

Define operations

Now you've reached the most important part of the tutorial; it's time to represent the Request/Reply pattern.

Both helloListener and reactionListener operations are set to receive events. However, in the case of reactionListener, you also want to represent the message sent back to the server. This is where the reply attribute comes into play.

Since both the request and reply function happens over the same WebSocket URL, both channel values stay the same. However, you can differentiate each operation's message by specifying the messages sent or received. Thus, you can say that for a reaction message received over the root channel, the reactionListener operation will reply with the acknowledge message over the same channel.

1operations:
2  helloListener:
3    action: receive
4    channel:
5      $ref: '#/channels/root'
6    messages:
7      - $ref: '#/channels/root/messages/hello'
8  reactionListener:
9    action: receive
10    channel: 
11      $ref: '#/channels/root'
12    messages:
13      - $ref: '#/channels/root/messages/reaction'
14    reply:
15      messages:
16        - $ref: '#/channels/root/messages/acknowledge'      
17      channel: 
18        $ref: '#/channels/root' 

Putting all this together, you have your AsyncAPI document ready to go!

1asyncapi: 3.0.0
2info:
3  title: Implement Request/Reply in an AsyncAPI document for a Slack app
4  version: 1.0.0
5  description: >
6    The Heart-Counter manages popular messages in a Slack workspace by
7    monitoring message reaction data. It also sends an acknowledgment message
8    back to the Slack Server to indicate it has received the message.
9servers:
10  production:
11    host: wss-primary.slack.com
12    pathname: /link
13    protocol: wss
14    description: Slack's server in Socket Mode for real-time communication
15channels:
16  root:
17    address: /
18    messages:
19      hello:
20        $ref: '#/components/messages/hello'
21      reaction:
22        $ref: '#/components/messages/reaction'
23      acknowledge:
24        $ref: '#/components/messages/acknowledge'
25    bindings:
26      ws:
27        query:
28          type: object
29          description: >-
30            Tokens are produced in the WebSocket URL generated from the
31            [apps.connections.open](https://api.slack.com/methods/apps.connections.open)
32            method from Slack's API
33          properties:
34            ticket:
35              type: string
36              description: Temporary token generated when connection is initiated
37              const: 13748dac-b866-4ea7-b98e-4fb7895c0a7f
38            app_id:
39              type: string
40              description: Unique identifier assigned to the Slack app
41              const: fe684dfa62159c6ac646beeac31c8f4ef415e4f39c626c2dbd1530e3a690892f
42operations:
43  helloListener:
44    action: receive
45    channel:
46      $ref: '#/channels/root'
47    messages:
48      - $ref: '#/channels/root/messages/hello'
49  reactionListener:
50    action: receive
51    channel:
52      $ref: '#/channels/root'
53    messages:
54      - $ref: '#/channels/root/messages/reaction'
55    reply:
56      messages:
57        - $ref: '#/channels/root/messages/acknowledge'
58      channel:
59        $ref: '#/channels/root'
60components:
61  messages:
62    reaction:
63      summary: Action triggered when the channel receives a new reaction-added event
64      payload:
65        $ref: '#/components/schemas/reaction'
66    hello:
67      summary: Action triggered when a successful WebSocket connection is established
68      payload:
69        $ref: '#/components/schemas/hello'
70    acknowledge:
71      summary: Acknowledgement response sent to Server
72      payload:
73        $ref: '#/components/schemas/acknowledge'
74  schemas:
75    hello:
76      type: object
77      properties:
78        type:
79          type: string
80          description: A hello string confirming WebSocket connection
81        connection_info:
82          type: object
83          properties:
84            app_id:
85              type: string
86        num_connections:
87          type: integer
88        debug_info:
89          type: object
90          properties:
91            host:
92              type: string
93            started:
94              type: string
95            build_number:
96              type: integer
97            approximate_connection_time:
98              type: integer
99    reaction:
100      type: object
101      properties:
102        envelope_id:
103          type: string
104          description: 'Unique ID assigned to payload'
105        payload:
106          type: object
107          description: 'Payload of the reaction added event'
108          properties:
109            token:
110              type: string
111            team_id:
112              type: string
113            event:
114              type: object
115              properties:
116                user:
117                  type: string
118                  description: User ID who performed this event
119                reaction:
120                  type: string
121                  description: The only reaction that you need is a heart emoji
122                item_user:
123                  type: string
124                  description: |
125                    User ID that created the original item that has been reacted
126                    to
127                item:
128                  type: object
129                  properties:
130                    channel:
131                      type: string
132                      description: Channel information of original message
133                    ts:
134                      type: string
135                      description: Timestamp information of original message
136                event_ts:
137                  type: string
138                  description: Reaction timestamp
139        type:
140          type: string
141        accepts_response_payload:
142          type: boolean
143    acknowledge:
144      type: object
145      properties:
146        envelope_id:
147          type: string
148          description: 'Unique ID of acknowledged payload'
149        payload:
150          type: object
151          description: 'Optional payload of event' 

Summary

Great job getting to the end! In this tutorial, you learned how to create an AsyncAPI document for a use case that implemented the Request-Reply messaging pattern. Now, you can explore this pattern with sub-patterns to see how it works with real-life use cases.

Was this helpful?
Help us improve the docs by adding your contribution.
OR
Github:AsyncAPICreate Issue on GitHub