We are working to document different WebSocket APIs we’ve come across using the AsyncAPI specification. The specification is new, and we are just beginning to understand how it all works, and we are learning a lot from the existing work of the contributors to the AsyncAPI project. They’ve recently added the ability to document event-driven WebSocket APIs, that will differ from other message-based, and even SSE streaming APIs. They all share a number of components but have unique needs which the AsyncAPI teams have moved recently to accommodate as part of the machine-readable specification. To help demonstrate what is possible when you document a WebSocket API using AsyncAPI, we wanted to share a definition for the Slack Real Time Messaging API they’ve published as part of their working examples in the Github repository for the Async API specification.
asyncapi: '1.2.0'
info:
title: Slack Real Time Messaging API
version: '1.0.0'
servers:
- url: https://slack.com/api/rtm.connect
scheme: https
schemeVersion: '1.1'
security:
- token: []
events:
receive:
- $ref: '#/components/messages/hello'
- $ref: '#/components/messages/connectionError'
- $ref: '#/components/messages/accountsChanged'
- $ref: '#/components/messages/botAdded'
- $ref: '#/components/messages/botChanged'
- $ref: '#/components/messages/channelArchive'
- $ref: '#/components/messages/channelCreated'
- $ref: '#/components/messages/channelDeleted'
- $ref: '#/components/messages/channelHistoryChanged'
- $ref: '#/components/messages/channelJoined'
- $ref: '#/components/messages/channelLeft'
- $ref: '#/components/messages/channelMarked'
- $ref: '#/components/messages/channelRename'
- $ref: '#/components/messages/channelUnarchive'
- $ref: '#/components/messages/commandsChanged'
- $ref: '#/components/messages/dndUpdated'
- $ref: '#/components/messages/dndUpdatedUser'
- $ref: '#/components/messages/emailDomainChanged'
- $ref: '#/components/messages/emojiRemoved'
- $ref: '#/components/messages/emojiAdded'
- $ref: '#/components/messages/fileChange'
- $ref: '#/components/messages/fileCommentAdded'
- $ref: '#/components/messages/fileCommentDeleted'
- $ref: '#/components/messages/fileCommentEdited'
- $ref: '#/components/messages/fileCreated'
- $ref: '#/components/messages/fileDeleted'
- $ref: '#/components/messages/filePublic'
- $ref: '#/components/messages/fileShared'
- $ref: '#/components/messages/fileUnshared'
- $ref: '#/components/messages/goodbye'
- $ref: '#/components/messages/groupArchive'
- $ref: '#/components/messages/groupClose'
- $ref: '#/components/messages/groupHistoryChanged'
- $ref: '#/components/messages/groupJoined'
- $ref: '#/components/messages/groupLeft'
- $ref: '#/components/messages/groupMarked'
- $ref: '#/components/messages/groupOpen'
- $ref: '#/components/messages/groupRename'
- $ref: '#/components/messages/groupUnarchive'
- $ref: '#/components/messages/imClose'
- $ref: '#/components/messages/imCreated'
- $ref: '#/components/messages/imMarked'
- $ref: '#/components/messages/imOpen'
- $ref: '#/components/messages/manualPresenceChange'
- $ref: '#/components/messages/memberJoinedChannel'
- $ref: '#/components/messages/message'
send:
- $ref: '#/components/messages/outgoingMessage'
components:
securitySchemes:
token:
type: httpApiKey
name: token
in: query
schemas:
attachment:
type: object
properties:
fallback:
type: string
color:
type: string
pretext:
type: string
author_name:
type: string
author_link:
type: string
format: uri
author_icon:
type: string
format: uri
title:
type: string
title_link:
type: string
format: uri
text:
type: string
fields:
type: array
items:
type: object
properties:
title:
type: string
value:
type: string
short:
type: boolean
image_url:
type: string
format: uri
thumb_url:
type: string
format: uri
footer:
type: string
footer_icon:
type: string
format: uri
ts:
type: number
messages:
hello:
summary: First event received upon connection.
payload:
type: object
properties:
type:
type: string
enum: ['hello']
connectionError:
summary: Event received when a connection error happens.
payload:
type: object
properties:
type:
type: string
enum: ['error']
error:
type: object
properties:
code:
type: number
msg:
type: string
accountsChanged:
summary: The list of accounts a user is signed into has changed.
payload:
type: object
properties:
type:
type: string
enum: ['accounts_changed']
botAdded:
summary: A bot user was added.
payload:
type: object
properties:
type:
type: string
enum: ['bot_added']
bot:
type: object
properties:
id:
type: string
app_id:
type: string
name:
type: string
icons:
type: object
additionalProperties:
type: string
botChanged:
summary: A bot user was changed.
payload:
type: object
properties:
type:
type: string
enum: ['bot_added']
bot:
type: object
properties:
id:
type: string
app_id:
type: string
name:
type: string
icons:
type: object
additionalProperties:
type: string
channelArchive:
summary: A channel was archived.
payload:
type: object
properties:
type:
type: string
enum: ['channel_archive']
channel:
type: string
user:
type: string
channelCreated:
summary: A channel was created.
payload:
type: object
properties:
type:
type: string
enum: ['channel_created']
channel:
type: object
properties:
id:
type: string
name:
type: string
created:
type: number
creator:
type: string
channelDeleted:
summary: A channel was deleted.
payload:
type: object
properties:
type:
type: string
enum: ['channel_deleted']
channel:
type: string
channelHistoryChanged:
summary: Bulk updates were made to a channel's history.
payload:
type: object
properties:
type:
type: string
enum: ['channel_history_changed']
latest:
type: string
ts:
type: string
event_ts:
type: string
channelJoined:
summary: You joined a channel.
payload:
type: object
properties:
type:
type: string
enum: ['channel_joined']
channel:
type: object
properties:
id:
type: string
name:
type: string
created:
type: number
creator:
type: string
channelLeft:
summary: You left a channel.
payload:
type: object
properties:
type:
type: string
enum: ['channel_left']
channel:
type: string
channelMarked:
summary: Your channel read marker was updated.
payload:
type: object
properties:
type:
type: string
enum: ['channel_marked']
channel:
type: string
ts:
type: string
channelRename:
summary: A channel was renamed.
payload:
type: object
properties:
type:
type: string
enum: ['channel_rename']
channel:
type: object
properties:
id:
type: string
name:
type: string
created:
type: number
channelUnarchive:
summary: A channel was unarchived.
payload:
type: object
properties:
type:
type: string
enum: ['channel_unarchive']
channel:
type: string
user:
type: string
commandsChanged:
summary: A slash command has been added or changed.
payload:
type: object
properties:
type:
type: string
enum: ['commands_changed']
event_ts:
type: string
dndUpdated:
summary: Do not Disturb settings changed for the current user.
payload:
type: object
properties:
type:
type: string
enum: ['dnd_updated']
user:
type: string
dnd_status:
type: object
properties:
dnd_enabled:
type: boolean
next_dnd_start_ts:
type: number
next_dnd_end_ts:
type: number
snooze_enabled:
type: boolean
snooze_endtime:
type: number
dndUpdatedUser:
summary: Do not Disturb settings changed for a member.
payload:
type: object
properties:
type:
type: string
enum: ['dnd_updated_user']
user:
type: string
dnd_status:
type: object
properties:
dnd_enabled:
type: boolean
next_dnd_start_ts:
type: number
next_dnd_end_ts:
type: number
emailDomainChanged:
summary: The workspace email domain has changed.
payload:
type: object
properties:
type:
type: string
enum: ['email_domain_changed']
email_domain:
type: string
event_ts:
type: string
emojiRemoved:
summary: A custom emoji has been removed.
payload:
type: object
properties:
type:
type: string
enum: ['emoji_changed']
subtype:
type: string
enum: ['remove']
names:
type: array
items:
type: string
event_ts:
type: string
emojiAdded:
summary: A custom emoji has been added.
payload:
type: object
properties:
type:
type: string
enum: ['emoji_changed']
subtype:
type: string
enum: ['add']
name:
type: string
value:
type: string
format: uri
event_ts:
type: string
fileChange:
summary: A file was changed.
payload:
type: object
properties:
type:
type: string
enum: ['file_change']
file_id:
type: string
file:
type: object
properties:
id:
type: string
fileCommentAdded:
summary: A file comment was added.
payload:
type: object
properties:
type:
type: string
enum: ['file_comment_added']
comment: {}
file_id:
type: string
file:
type: object
properties:
id:
type: string
fileCommentDeleted:
summary: A file comment was deleted.
payload:
type: object
properties:
type:
type: string
enum: ['file_comment_deleted']
comment:
type: string
file_id:
type: string
file:
type: object
properties:
id:
type: string
fileCommentEdited:
summary: A file comment was edited.
payload:
type: object
properties:
type:
type: string
enum: ['file_comment_edited']
comment: {}
file_id:
type: string
file:
type: object
properties:
id:
type: string
fileCreated:
summary: A file was created.
payload:
type: object
properties:
type:
type: string
enum: ['file_created']
file_id:
type: string
file:
type: object
properties:
id:
type: string
fileDeleted:
summary: A file was deleted.
payload:
type: object
properties:
type:
type: string
enum: ['file_deleted']
file_id:
type: string
event_ts:
type: string
filePublic:
summary: A file was made public.
payload:
type: object
properties:
type:
type: string
enum: ['file_public']
file_id:
type: string
file:
type: object
properties:
id:
type: string
fileShared:
summary: A file was shared.
payload:
type: object
properties:
type:
type: string
enum: ['file_shared']
file_id:
type: string
file:
type: object
properties:
id:
type: string
fileUnshared:
summary: A file was unshared.
payload:
type: object
properties:
type:
type: string
enum: ['file_unshared']
file_id:
type: string
file:
type: object
properties:
id:
type: string
goodbye:
summary: The server intends to close the connection soon.
payload:
type: object
properties:
type:
type: string
enum: ['goodbye']
groupArchive:
summary: A private channel was archived.
payload:
type: object
properties:
type:
type: string
enum: ['group_archive']
channel:
type: string
groupClose:
summary: You closed a private channel.
payload:
type: object
properties:
type:
type: string
enum: ['group_close']
user:
type: string
channel:
type: string
groupHistoryChanged:
summary: Bulk updates were made to a private channel's history.
payload:
type: object
properties:
type:
type: string
enum: ['group_history_changed']
latest:
type: string
ts:
type: string
event_ts:
type: string
groupJoined:
summary: You joined a private channel.
payload:
type: object
properties:
type:
type: string
enum: ['group_joined']
channel:
type: object
properties:
id:
type: string
name:
type: string
created:
type: number
creator:
type: string
groupLeft:
summary: You left a private channel.
payload:
type: object
properties:
type:
type: string
enum: ['group_left']
channel:
type: string
groupMarked:
summary: A private channel read marker was updated.
payload:
type: object
properties:
type:
type: string
enum: ['group_marked']
channel:
type: string
ts:
type: string
groupOpen:
summary: You opened a private channel.
payload:
type: object
properties:
type:
type: string
enum: ['group_open']
user:
type: string
channel:
type: string
groupRename:
summary: A private channel was renamed.
payload:
type: object
properties:
type:
type: string
enum: ['group_rename']
channel:
type: object
properties:
id:
type: string
name:
type: string
created:
type: number
groupUnarchive:
summary: A private channel was unarchived.
payload:
type: object
properties:
type:
type: string
enum: ['group_unarchive']
channel:
type: string
user:
type: string
imClose:
summary: You closed a DM.
payload:
type: object
properties:
type:
type: string
enum: ['im_close']
channel:
type: string
user:
type: string
imCreated:
summary: A DM was created.
payload:
type: object
properties:
type:
type: string
enum: ['im_created']
channel:
type: object
properties:
id:
type: string
name:
type: string
created:
type: number
creator:
type: string
user:
type: string
imMarked:
summary: A direct message read marker was updated.
payload:
type: object
properties:
type:
type: string
enum: ['im_marked']
channel:
type: string
ts:
type: string
imOpen:
summary: You opened a DM.
payload:
type: object
properties:
type:
type: string
enum: ['im_open']
channel:
type: string
user:
type: string
manualPresenceChange:
summary: You manually updated your presence.
payload:
type: object
properties:
type:
type: string
enum: ['manual_presence_change']
presence:
type: string
memberJoinedChannel:
summary: A user joined a public or private channel.
payload:
type: object
properties:
type:
type: string
enum: ['member_joined_channel']
user:
type: string
channel:
type: string
channel_type:
type: string
enum:
- C
- G
team:
type: string
inviter:
type: string
memberLeftChannel:
summary: A user left a public or private channel.
payload:
type: object
properties:
type:
type: string
enum: ['member_left_channel']
user:
type: string
channel:
type: string
channel_type:
type: string
enum:
- C
- G
team:
type: string
message:
summary: A message was sent to a channel.
payload:
type: object
properties:
type:
type: string
enum: ['message']
user:
type: string
channel:
type: string
text:
type: string
ts:
type: string
attachments:
type: array
items:
$ref: '#/components/schemas/attachment'
edited:
type: object
properties:
user:
type: string
ts:
type: string
outgoingMessage:
summary: A message was sent to a channel.
payload:
type: object
properties:
id:
type: number
type:
type: string
enum: ['message']
channel:
type: string
text:
type: string
The specification is pretty verbose, but it provides a great example of a robust WebSockets API, that we can all reverse engineer and learn about how to properly define WebSocket APIs using the specification format. Outlining how to properly define the events, and their corresponding messages, providing a machine-readable definition for a WebSocket API.
We have 50 WebSocket APIs we’ve worked to craft AsyncAPI definitions for. We are working to publish them as a single collection of definitions as part of the Streamdata.io API Gallery. Once up, we’ll publish a story on the collection, providing other examples of WebSocket APIs that have been documented using AsyncAPI. We see AsyncAPI being just as important to the evolution of the API sectors as OpenAPI, but providing an accompanying specification for defining streaming, event, and message-based APIs. If you are in the business of delivering streaming, event-based, or message-based APIs we recommend getting involved and contribute to the community.