DEV Community

Matt Butcher for Fermyon

Posted on with Sohan • Updated on

Build a Slack Emoji Bot in 20 Lines of Code

My colleague Rajat recently built a Behind The Scenes photo sharing webapp. The idea behind this app was simple - At Fermyon, we’re a fully remote company. We tend to use Slack for all our communication and we have a channel named #behind-the-scenes where we share photos from all our travel to conferences, and meetups etc. The idea was to create a web app that was a front end to the photos shared on that channel. (You can check out this tutorial on how Rajat built this using Spin and Nuxt.js)

A cool feature of this workflow was that not all photos shared on the channel were displayed on the Behind The Scenes app. Photos would only appear on the site if they were ‘signed off’ by the person who posted the image. This sign off method was rather clever - It would be via a specific Slack emoji reaction! I loved that little implementation detail so set out to see how it was built out.

The Behind the Scenes app in action

Here’s how you can can build a webhook that is triggered with a Slack emoji reaction, in less than 20 lines of code!

Create a Slack App

To build this webhook you first need to create a Slack app.

1. Go to api.slack.com and click on ‘Your Apps’

Slack's configuration

2. Click the ‘Create New App’ button and add an App Name (you can change this later) and also a workspace that you want to develop your app in. Ensure you have the permissions to add App integrations to Slack. Personally, I prefer having a private Slack workspace for testing out bots as I’d rather not alarm my colleagues with an erratic Slack bot 🙃

Find "Your Apps"

Create a new app

3. Nice! Your Slack app is created. We now need to add an Event Subscription to it so that it can detect when an emoji reaction is added to a message. Click on the ‘Add features and functionality’ section and then the ‘Event Subscriptions’ button

Add basic information

4. The Slack API has an interesting way to ensure only ‘Verified’ URLs can respond to Events. Essentially, their API sends a HTTP POST request to your endpoint, that contains a challenge parameter. They expect your endpoint to respond with the same challenge value to verify your endpoint.

This is what the payload looks like:

{
    "token": "Jhj5dZrVaK7ZwHHjRyZWjbDl",
    "challenge": "3eZbrw1aBm2rZgRNFdxV2595E9CY3gmdALWMmHkvFXO7tYXAYM8P",
    "type": "url_verification"
}
Enter fullscreen mode Exit fullscreen mode

See the documentation here for more info.

Event Subscriptions

Hold on, I need a backend endpoint to verify the Events API and then when someone adds an emoji to a Slack message.

Here’s where Spin comes in 👉🏽

Create an endpoint using Spin

Spin is an open source developer tool for building and running serverless applications powered by WebAssembly. To install Spin, check out the guide here.

1. Once you’ve installed Spin, let’s create a new app. This guide has code samples in Python but you can choose any of the other languages in the Spin SDK to get started:

spin new 
Pick a template to start your application with: http-py (HTTP request handler using Python)
Enter a name for your new application: reaction-emoji-bot
Description: 
HTTP path: /...
Enter fullscreen mode Exit fullscreen mode
cd reaction-emoji-bot
code .
Enter fullscreen mode Exit fullscreen mode

2. That was easy! Now let’s get our hands dirty with some code. Open the folder in your favourite code editor and look for app.py which is the starting point for your code. We have to first write code to verify the Slack Events API. We can do so by parsing the request object for the challenge parameter and returning it via the response

def handle_request(request):
    data = json.loads(request.body)
    challenge = data.get('challenge', None)
    return Response(200,
                    {"content-type": "text/plain"},
                    bytes(challenge, "utf-8"))
Enter fullscreen mode Exit fullscreen mode

3. The code above is straightforward - You can extract the challenge parameter by parsing the request.body . The response is literally just the challenge parameter. The Slack API is actually flexible in how you can send this value back. According to them you can verify the request's authenticity and then respond in plaintext or with application/x-www-form-urlencoded or even in JSON.

  1. Given that this needs to be a ‘live’ endpoint - we have to build and deploy this. Go back to your terminal and type in spin build which will build your Spin app. In case you’ve built the above using TypeScript, do a npm install before to install some dependancies.
  2. Now that the Spin app is built, deploying it to the cloud is straightforward. Just do a spin deploy and the app deploys to the Fermyon Cloud. (Assuming you’ve already logged in to the Fermyon Cloud)
> spin deploy 
Uploading reaction-emoji-bot version 0.1.0 to Fermyon Cloud...
Deploying...
Waiting for application to become ready.................. ready
Available Routes:
  reaction-emoji-bot: https://reaction-emoji-bot.fermyon.app (wildcard) 
Enter fullscreen mode Exit fullscreen mode

Congratulations! Your endpoint is now live. All we need to do now is give the appropriate permissions for your Slack app to access messages, and then write code to listen to the emoji-added event.

Listening to the Events API

1. Let’s first give your Slack App permissions to read messages on Slack. On api.slack.com, click on ‘Oauth & Permissions’ in the left menu that’s in the ‘Features’ section.

2. Scroll down to the ‘Scopes’ section and add the following scopes to your Slack App. Depending on what your app does, it may require more permissions.

chat:write, im:history, incoming-webhook, reactions:read
Enter fullscreen mode Exit fullscreen mode

Scopes

You also need to subscribe to bot events. In the ‘Event Subscriptions’ section, scroll down to ‘Subscribe to bot events’ and add the following.

message.im, reaction_added
Enter fullscreen mode Exit fullscreen mode

Again, if you expand the scope of your bot, ensure you add the relevant events.

Subscribe to Bot Events

3. Now that your app has permissions, you can write some code in your Spin app to listen to events such as a reaction emoji that’s added to a message. Go back to your code editor and add the following code:

def handle_request(request):
    json_data = request.body.decode('utf-8')
    # Parse the JSON string
    data = json.loads(json_data)

    # Access the 'reaction' value
    reaction_value = data['event']['reaction']

    # Print the result
    print(reaction_value) 

    # do something
Enter fullscreen mode Exit fullscreen mode

The code again is straightforward. When any event occurs, there is a HTTP POST request with a JSON payload that looks something like this (I’ve redacted some tokens)

The event parameter has the type of event as well as the specifics, in this case the reaction

{
    'token': 'XXXXXXXX',
    'team_id': 'XXXXXXXX',
    'context_team_id': 'XXXXXXXX',
    'context_enterprise_id': None,
    'api_app_id': 'XXXXXXXX',
    '**event**': {
        **'type': 'reaction_added',**
        'user': 'XXXXXXXX',
        **'reaction': 'white_check_mark',**
        'item': {
            'type': 'message',
            'channel': 'XXXXXXXX',
            'ts': 'XXXXXXXX'
        },
        'item_user': 'U06CRMCJW',
        'event_ts': 'XXXXXXXX'
    },
    'type': 'event_callback',
    'event_id': 'XXXXXXXX',
    'event_time': 17035280,
    'authorizations': [{
        'enterprise_id': None,
        'team_id': 'XXXXXXXX',
        'user_id': 'XXXXXXXX',
        'is_bot': True,
        'is_enterprise_install': False
    }],
    'is_ext_shared_channel': False,
    'event_context': '4-XXXXXXXX'
}
Enter fullscreen mode Exit fullscreen mode

The Python code above just parses the JSON to extract the reaction. You can choose to do anything once you’ve received an event with the type of emoji reaction that has been added.

For example: Approve a post if someone adds a ✅ emoji.

4. Slack requires the endpoint for verification to be the same as the endpoint that is listening to any events. So we can route a request based on the payload. Just add this if condition. Again, if you are listening to multiple events it might be better to use a switch case or a different method of routing. Check out Rajat’s code here where he’s done the same

from spin_http import Request, Response, http_send
import json

def handle_request(request):
    json_data = request.body.decode('utf-8')
    data = json.loads(json_data)

    # Check if it's a URL verification request
    if 'challenge' in data:
        challenge = data.get('challenge', None)
        return Response(200, {"content-type": "text/plain"}, bytes(challenge, "utf-8"))
    else:
        # It's an event notification
        # Access the 'reaction' value
        reaction_value = data['event']['reaction']
        print(reaction_value)

        # Do something fun with the emoji reaction here
Enter fullscreen mode Exit fullscreen mode

5. You’re almost there! Let’s spin build and spin deploy your app. Once that’s done, go to your Slack Apps and add your app to the workspace to test it out. In your app’s page, click on ‘Install App’ in the left menu and then choose the Slack Workspace and channel your bot can post to.

Choose a channel

6. You can double check to see if the bot has been added to the channel

Reaction emoji was added

To debug your code or look at the logs, you can login to [cloud.fermyon.co](http://cloud.fermyon.co)m and click on the app that you’ve just deployed. Click on logs on the left and you will see that all your print statements and events are logged here in real-time. You can even have a custom domain for this endpoint by clicking on the Custom Domains section in the left menubar.

Next Steps

That was a simple tutorial on how you can create a simple webhook that listens to an emoji reaction. You can expand this to do all sorts of cool Slash commands in Slack. You can also use this with custom emojis. You’ll notice in the first screenshot at the top of this page, there’s a 🍇 emoji. That’s the reaction emoji we used (Ask us why in the comments, there’s a fun story there 😄)

Also, check out how fast the responses are! This is because Spin uses WebAssembly which has no cold-starts. This makes it ideal for Slack bots and webhooks.

*In Part II of this article, we will continue this and see what we can do when a user adds a emoji to a message. *

Let us know what type of Slack bots you are building. We’d love to hear from you <3

Top comments (1)

Collapse
 
debadyuti profile image
Deb

Awesome tutorial. I am about to publish a very similar tutorial. Now I have to complete it... :)