Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/hacksoftware/europython-2021-training
Repository to hold materials for the "Building a practical Slack bot with Python & FastAPI" training.
https://github.com/hacksoftware/europython-2021-training
Last synced: about 1 month ago
JSON representation
Repository to hold materials for the "Building a practical Slack bot with Python & FastAPI" training.
- Host: GitHub
- URL: https://github.com/hacksoftware/europython-2021-training
- Owner: HackSoftware
- License: mit
- Created: 2021-07-24T13:42:04.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2021-07-26T07:20:26.000Z (over 3 years ago)
- Last Synced: 2024-03-27T13:13:12.149Z (9 months ago)
- Language: Python
- Size: 25.4 KB
- Stars: 10
- Watchers: 2
- Forks: 7
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# EuroPython 2021 Training
This is the repository with materials for the [Building a practical Slack bot with Python & FastAPI
](https://ep2021.europython.eu/talks/9xzPSHe-building-a-practical-slack-bot-with-python-fastapi-training/) training.[Slides can be found here](https://docs.google.com/presentation/d/1h3mHULQQrtyvmiTPuneqhpEH3l9yzpLIgL-r_bUCHSg/edit?usp=sharing)
## Overview
![Slack Chat Bot@2x](https://user-images.githubusercontent.com/387867/126901049-4a965bad-41b4-4168-8ba7-05cc4322dee3.png)
## Step 0 - OS setup
This training is using the following OS tools:
1. `curl` - for making HTTP calls.
1. `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).
1. Create a fresh virtual environment for the training.
1. 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](https://github.com/pyenv/pyenv)
1. [pyenv-virtualenv](https://github.com/pyenv/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:
```python
from fastapi import Body, FastAPI, Request, Responseapp = 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):
```bash
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.
1. 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:
```json
{
"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
1. Click on the `Create an app` button
1. Click on the `Create New App` button
1. Select `From scratch`
1. Type `EuroPython Bot` in the `App Name` field
1. Select your newly created workspaceAfter following those steps, you should end up with a screen that looks something like that:
![image](https://user-images.githubusercontent.com/387867/126795187-59ed6d31-e0a2-4ebe-9713-727a525b4762.png)
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`](https://ngrok.com/) - 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](https://ngrok.com/download) 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.
1. Turn it on.
1. Paste your `ngrok` url, pointing to the `/echo` endpoint. In my case, that's `https://c153a68641fd.ngrok.io/echo`
1. If our server & `ngrok` are running, you'll see a green `Verified` in Slack. Check the `ngrok` shell - you should see a request there.
1. Now click on `Subscribe to bot events`, click `Add Bot User Event` and select `app_mention`.
1. Hit `Save Changes`.
1. 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`
1. Click the `Install to Workspace` button.
1. Click `Allow`.
1. 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.
1. `@` the bot and write something.
1. Check your FastAPI console.The event payload that we received should look something like that:
```json
{
"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.
1. Whenever someone mentions our bot **in a thread**, we want to reply in the same thread with a message.
1. **[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?](https://api.slack.com/authentication/basics#start)
1. [Listening to the `app_mention` event](https://api.slack.com/events/app_mention)
1. [Sending messages](https://api.slack.com/messaging/sending)
1. [Retrieving individual messages](https://api.slack.com/messaging/retrieving#individual_messages)### Hints
Making a call to Slack requires obtaining `Bot User OAuth Token` from the settings page:
![europython](https://user-images.githubusercontent.com/387867/126901159-808b77db-04f2-4b3d-85d0-e6a851155959.png)
Since this is a secret, in order to manage secrets for our app, we recommend using `.env` file and for parsing it:
```python
from dotenv import dotenv_valuesconfig = dotenv_values(".env") # config = {"USER": "foo", "EMAIL": "[email protected]"}
```## 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](https://api.slack.com/authentication/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
1. There's an offical [Python Slack SDK](https://github.com/slackapi/python-slack-sdk) that you can use.
1. You can also use [`bolt-python`](https://github.com/slackapi/bolt-python) which is a framework for building Slack apps.
1. [The official documentation, of course](https://api.slack.com/)