Create an AsyncAPI document for a Slackbot with WebSocket

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

Introduction

In this tutorial, you will learn how to write an AsyncAPI document designed for a Slack application that operates in Socket Mode. The aim is to help you grasp a real-world application of AsyncAPI with the WebSocket protocol. You will learn how to write an AsyncAPI document for a consumer-only application receiving a stream of messages from a WebSocket server. You will also learn why the AsyncAPI bindings feature exists and how to use it.

Consider a scenario where you are in charge of maintaining a highly active Slack workspace. You want an easy way to keep track of the popular messages across all channels, but doing this manually would be difficult. To simplify this process, you will build a Slackbot called Heart-Counter that actively monitors reactions added to a message and determines its popularity by counting the reactions of the “heart” emoji.

Here’s a visual representation of how the Heart-Counter should work:

Background context

WebSocket is a communication protocol that enables simultaneous bidirectional data exchange between a client and a server over a single, long-lived connection. Unlike HTTP, which relies on the request-response model, WebSocket is ideal for scenarios where real-time, interactive, and low-latency communication is necessary.

In Slack, WebSocket is employed as part of its Socket Mode feature to facilitate real-time notifications between Slack's servers and third-party applications or bots. The Slack Event API is a tool that lets you receive real-time notifications of specific events in a Slack workspace such as messages, reactions, and user presence changes.

Define AsyncAPI version, API information, and server

You start your AsyncAPI document by specifying the AsyncAPI version and essential information about your Slack application's API, which includes details such as the title, version, and description.

The servers section allows you to define the protocol and specify information about the URLs your application will use, such as host, pathname, protocol, and description.

Remember

The WebSocket URL is generated by invoking the apps.connections.open method from Slack’s API. You use the authentication tokens obtained during the configuration of your Slackbot to generate this URL.

1asyncapi: '3.0.0'
2info:
3  title: Create an AsyncAPI document for a Slackbot with WebSocket
4  version: '1.0.0'
5  description:  |
6    The Heart-Counter manages popular messages in a Slack workspace by monitoring message reaction data
7servers:
8  production:
9    host: wss-primary.slack.com
10    pathname: /link
11    protocol: wss
12    description: Slack's server in Socket Mode for real-time communication 

Define messages and schemas

Your AsyncAPI document needs to be very clear on the type of event it is expected to receive. Here's where the messages component steps in. Using the payload property, you can specify what these events should look like, their structure, and what content they carry.

The payload attribute specifies the name, format, and description of all the expected properties. Heart-Counter starts the popularity count of a message by validating if the reaction property set in the reaction schema definition corresponds to "heart".

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  schemas:
12    hello:
13      type: object
14      properties:
15        type:
16          type: string
17          description: A hello string confirming WebSocket connection
18        connection_info:
19          type: object
20          properties:
21            app_id:
22              type: string
23        num_connections:
24          type: integer
25        debug_info:
26          type: object
27          properties:
28            host:
29              type: string
30            started:
31              type: string
32            build_number:
33              type: integer
34            approximate_connection_time:
35              type: integer
36    reaction:
37      type: object
38      properties:
39        user:
40          type: string
41          description: User ID who performed this event
42        reaction:
43          type: string
44          description: The only reaction that we need is a heart emoji
45        item_user:
46          type: string
47          description: User ID that created the original item that has been reacted to
48        item:
49          type: object
50          properties:
51            channel:
52              type: string
53              description: Channel information of original message
54            ts:
55              type: string
56              description: Timestamp information of original message
57        event_ts:
58          type: string
59          description: Reaction timestamp

Define channels and bindings

The channels attribute defines a communication channel for the event. The address specifies where the channel is tuned in to receive messages while the messages property defines a key-value pair where each key corresponds to the event it's set up to handle.

The WebSocket URL generated for Heart-Counter includes authentication tokens. This information is represented using query parameters. Query parameters are specific to HTTP protocol and partially to WebSocket, which uses HTTP to connect client and server. Since this is protocol-specific information, you must use an AsyncAPI feature called bindings that enables you to provide protocol-specific information inside the AsyncAPI document using the bindings attribute. By utilizing the query object from the WebSocket binding, you can outline the parameters needed for the connection and the conditions they must meet.

1channels:
2  root:
3    address: /
4    messages:
5      hello:
6        $ref: '#/components/messages/hello'
7      reaction:
8        $ref: '#/components/messages/reaction'
9    bindings:
10      ws:
11        query:
12          type: object
13          description: Tokens are produced in the WebSocket URL generated from the [apps.connections.open](https://api.slack.com/methods/apps.connections.open) method from Slack’s API
14          properties:
15            ticket:
16              type: string
17              description: Temporary token generated when connection is initiated
18              const: '13748dac-b866-4ea7-b98e-4fb7895c0a7f'
19            app_id:
20              type: string
21              description: Unique identifier assigned to the Slack app
22              const: 'fe684dfa62159c6ac646beeac31c8f4ef415e4f39c626c2dbd1530e3a690892f' 

Define operations

The operation property is all about defining specific tasks your application can perform. Essentially, it's how the Heart-Counter interacts with Slack.

In this example, the helloListener operation keeps an eye out for the message sent by the Slack server when a WebSocket connection is successfully established. On the other hand, the reactionListener is focused on the reaction_added event type.

Your Slack application is designed to be notified of events within your workspace. It subscribes to a specific event type and uses Slack's Event API. In this case, both operations' action property is set to receive events.

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' 

Congratulations, you've completed the tutorial! Putting these blocks together gives you an AsyncAPI document all ready to go.

1asyncapi: '3.0.0'
2info:
3  title: Create an AsyncAPI document for a Slackbot with WebSocket
4  version: '1.0.0'
5  description:  |
6    The Heart-Counter manages popular messages in a Slack workspace by monitoring message reaction data.
7servers:
8  production:
9    host: wss-primary.slack.com
10    pathname: /link
11    protocol: wss
12    description: Slack's server in Socket Mode for real-time communication
13channels:
14  root:
15    address: /
16    messages:
17      hello:
18        $ref: '#/components/messages/hello'
19      reaction:
20        $ref: '#/components/messages/reaction'
21    bindings:
22      ws:
23        query:
24          type: object
25          description: Tokens are produced in the WebSocket URL generated from the [apps.connections.open](https://api.slack.com/methods/apps.connections.open) method from Slack’s API
26          properties:
27            ticket:
28              type: string
29              description: Temporary token generated when connection is initiated
30              const: '13748dac-b866-4ea7-b98e-4fb7895c0a7f'
31            app_id:
32              type: string
33              description: Unique identifier assigned to the Slack app
34              const: 'fe684dfa62159c6ac646beeac31c8f4ef415e4f39c626c2dbd1530e3a690892f'
35operations:
36  helloListener:
37    action: receive
38    channel:
39      $ref: '#/channels/root'
40    messages:
41      - $ref: '#/channels/root/messages/hello'
42  reactionListener:
43    action: receive
44    channel:
45      $ref: '#/channels/root'
46    messages:
47      - $ref: '#/channels/root/messages/reaction'
48components:
49  messages:
50    reaction:
51      summary: Action triggered when the channel receives a new reaction-added event
52      payload:
53        $ref: '#/components/schemas/reaction'
54    hello:
55      summary: Action triggered when a successful WebSocket connection is established
56      payload:
57        $ref: '#/components/schemas/hello'
58  schemas:
59    hello:
60      type: object
61      properties:
62        type:
63          type: string
64          description: A hello string confirming WebSocket connection
65        connection_info:
66          type: object
67          properties:
68            app_id:
69              type: string
70            num_connections:
71              type: integer
72            debug_info:
73              type: object
74              properties:
75                host:
76                  type: string
77                started:
78                  type: string
79                build_number:
80                  type: integer
81                approximate_connection_time:
82                  type: integer
83    reaction:
84      type: object
85      properties:
86        user:
87          type: string
88          description: User ID who performed this event
89        reaction:
90          type: string
91          description: The only reaction that we need is a heart emoji
92        item_user:
93          type: string
94          description: User ID that created the original item that has been reacted to
95        item:
96          type: object
97          properties:
98            channel:
99              type: string
100              description: Channel information of original message
101            ts:
102              type: string
103              description: Timestamp information of original message
104        event_ts:
105          type: string
106          description: Reaction timestamp 

Summary

In this tutorial, you learned to create an AsyncAPI document for a Slackbot using WebSocket in Socket Mode. You gained practical insights into the functionality of operations, channels, messages, and schemas. Now you're equipped to handle real-world applications that facilitate bidirectional real-time data exchange, such as chatbots and live-streaming platforms.

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