Skip to content

Repository to hold materials for the "Building a practical Slack bot with Python & FastAPI" training.

License

Notifications You must be signed in to change notification settings

HackSoftware/EuroPython-2021-Training

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

EuroPython 2021 Training

This is the repository with materials for the Building a practical Slack bot with Python & FastAPI training.

Slides can be found here

Overview

Slack Chat Bot@2x

Step 0 - OS setup

This training is using the following OS tools:

  1. curl - for making HTTP calls.
  2. jq - for pretty printing JSON results.

But in case you don't have them, it's not a problem and we don't need them for the final solution.

Step 1 - Python setup

To run everything from here, we recommend the following Python setup:

  1. Use the latest Python version (3.9.6 by the time of writing).
  2. Create a fresh virtual environment for the training.
  3. Create a fresh directory to contain everything for this training.

To achieve the points above, use the tools that you use everyday.

We recommend using:

  1. pyenv
  2. pyenv-virtualenv

Step 2 - Slack setup

We are going to need a test Slack workspace for this training.

The best approach here is to create a brand new one, but feel free to reuse already existing one.

Step 3 - FastAPI setup

Now, we are going to create one small FastAPI app and expose an endpoint to test with.

First, we need to install the dependencies:

pip install fastapi
pip install uvicorn[standard] # or uvicorn\[standard\] depending on your shell

Then, in the working directory, create a file called main.py with the following contents:

from fastapi import Body, FastAPI, Request, Response

app = FastAPI()


@app.post("/echo")
async def echo(request: Request, response: Response, data=Body(...)):
    raw_body = await request.body()
    body = raw_body.decode("utf-8")

    print(data)

    return {
        "data": data,
        "raw_body": body,
        "headers": request.headers
    }

Now, lets run our server:

uvicorn main:app --reload

And test it by issuing a POST request via curl (or any other HTTP client that you find suitable):

curl -s -X POST -H "Content-Type: application/json" -d '{"key": "value"}' http://localhost:8000/echo

Few things to note:

  1. We are using -s for a "silent" curl output, skipping the progress bar.
  2. We are sending the Content-Type header, set to application/json, because this triggers FastAPI to parse the JSON into the body argument.

An example response would look like that:

{
  "data": {
    "key": "value"
  },
  "raw_body": "{\"key\": \"value\"}",
  "headers": {
    "host": "localhost:8000",
    "user-agent": "curl/7.58.0",
    "accept": "*/*",
    "content-type": "application/json",
    "content-length": "16"
  }
}

Step 4 - Slack app setup

Now, we are going to setup an app within our new Slack workspace, so we can start communicating with our server.

  1. Navigate to https://api.slack.com/
  2. Click on the Create an app button
  3. Click on the Create New App button
  4. Select From scratch
  5. Type EuroPython Bot in the App Name field
  6. Select your newly created workspace

After following those steps, you should end up with a screen that looks something like that:

image

Before we continue further, we'll need 1 more thing.

Step 5 - ngrok setup

Since we are going to listen for events from Slack & those events are going to be HTTP POST requests, we need a way to tell Slack how to find our localhost:8000 server.

One way of doing this is using ngrok - a piece of software that's going to create a tunnel to our localhost & give us a public url, that we'll post in Slack.

Navigate to the download page and download ngrok for you OS & platform.

Once extracted, in a new shell, while our FastAPI server is running, type:

./ngrok http 8000

This will run ngrok and present us with the public url. Copy that url.

Step 6 - Testing if we have integrated correctly

Now, back to Slack setup:

  1. Go to the Event Subscriptions option.
  2. Turn it on.
  3. Paste your ngrok url, pointing to the /echo endpoint. In my case, that's https://c153a68641fd.ngrok.io/echo
  4. If our server & ngrok are running, you'll see a green Verified in Slack. Check the ngrok shell - you should see a request there.
  5. Now click on Subscribe to bot events, click Add Bot User Event and select app_mention.
  6. Hit Save Changes.
  7. Leave the page open, since we'll come back here to add additional things.

Now, lets wire everything together, so we can start developing:

  1. In the app settings, navigate to Settings -> Basic Information
  2. Click the Install to Workspace button.
  3. Click Allow.
  4. Every time we change the permissions or scopes, we'll have to redo this entire process.

Now, open up the Slack workspace:

  1. Add the bot (type /add in the channel & click on the action item) to a random channel.
  2. @ the bot and write something.
  3. Check your FastAPI console.

The event payload that we received should look something like that:

{
    "token": "C2lhacRaergBLDrNglaNtVYQ",
    "team_id": "T028KF61U7R",
    "api_app_id": "A0290D2N9B4",
    "event": {
        "client_msg_id": "7f025cc5-2f1c-41c9-9ad9-f78d86c13b49",
        "type": "app_mention",
        "text": "<@U0290LLS803> hello :wave:",
        "user": "U028TEER6KY",
        "ts": "1627050528.001000",
        "team": "T028KF61U7R",
        "blocks": [
            {
                "type": "rich_text",
                "block_id": "UBr7f",
                "elements": [
                    {
                        "type": "rich_text_section",
                        "elements": [
                            {
                                "type": "user",
                                "user_id": "U0290LLS803"
                            },
                            {
                                "type": "text",
                                "text": " hello "
                            },
                            {
                                "type": "emoji",
                                "name": "wave"
                            }
                        ]
                    }
                ]
            }
        ],
        "channel": "C028TEHTWKG",
        "event_ts": "1627050528.001000"
    },
    "type": "event_callback",
    "event_id": "Ev029Q5P36BA",
    "event_time": 1627050528,
    "authorizations": [
        {
            "enterprise_id": null,
            "team_id": "T028KF61U7R",
            "user_id": "U0290LLS803",
            "is_bot": true,
            "is_enterprise_install": false
        }
    ],
    "is_ext_shared_channel": false,
    "event_context": "3-app_mention-T028KF61U7R-A0290D2N9B4-C028TEHTWKG"
}

This means we are now ready with our setup and can start adding funcitonality back.

Step 7 - Implementing bot behavior (TASKS START HERE)

Now, it's time for our tasks.

We want to implement the following general behavior:

  1. Whenever someone mentions our bot, we want to reply in the channel with a message.
  2. Whenever someone mentions our bot in a thread, we want to reply in the same thread with a message.
  3. [BONUS TASK] Whenever someone mentions our bot, start a new thread by replying to that user.

In order to do that, we want to be making HTTP calls to the Slack API via requests, so we need to do:

pip install requests

Documentation links to help

Extracted documentation links to help you navigate to the proper stuff to look at:

  1. What is a Slack app?
  2. Listening to the app_mention event
  3. Sending messages
  4. Retrieving individual messages

Hints

Making a call to Slack requires obtaining Bot User OAuth Token from the settings page:

europython

Since this is a secret, in order to manage secrets for our app, we recommend using .env file and https://github.com/theskumar/python-dotenv for parsing it:

from dotenv import dotenv_values

config = dotenv_values(".env")  # config = {"USER": "foo", "EMAIL": "foo@example.org"}

Step 8 - Validate Slack requests

Everything is great, but our API is public, meaning anyone can call it and start sending messages to our Slack.

We want to prevent this & your next task is to implement request verification!

Documentation links to help

  1. Verifying requests from Slack

Step 9 - Wrapping it up and further references

That's about it.

Materials for further references:

  1. Since we are using FastAPI with async, you can go & replace requests with something that's async, like https://docs.aiohttp.org/en/stable/
  2. There's an offical Python Slack SDK that you can use.
  3. You can also use bolt-python which is a framework for building Slack apps.
  4. The official documentation, of course

About

Repository to hold materials for the "Building a practical Slack bot with Python & FastAPI" training.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages