diff --git a/docs/content/building-an-app.md b/docs/content/building-an-app.md new file mode 100644 index 000000000..deb3146b9 --- /dev/null +++ b/docs/content/building-an-app.md @@ -0,0 +1,483 @@ +--- +title: Building an App with Bolt for Python +sidebar_label: Building an App +--- + +# Building an App with Bolt for Python + +This guide is meant to walk you through getting up and running with a Slack app using Bolt for Python. Along the way, we’ll create a new Slack app, set up your local environment, and develop an app that listens and responds to messages from a Slack workspace. + +When you're finished, you'll have created the [Getting Started app](https://github.com/slackapi/bolt-python/tree/main/examples/getting_started) to run, modify, and make your own. ⚡️ + +--- + +### Create an app {#create-an-app} +First thing's first: before you start developing with Bolt, you'll want to [create a Slack app](https://api.slack.com/apps/new). + +:::tip[A place to test and learn] + +We recommend using a workspace where you won't disrupt real work getting done — [you can create a new one for free](https://slack.com/get-started#create). + +::: + +After you fill out an app name (_you can change it later_) and pick a workspace to install it to, hit the `Create App` button and you'll land on your app's **Basic Information** page. + +This page contains an overview of your app in addition to important credentials you'll need later. + +![Basic Information page](/img/boltpy/basic-information-page.png "Basic Information page") + +Look around, add an app icon and description, and then let's start configuring your app 🔩 + +--- + +### Tokens and installing apps {#tokens-and-installing-apps} +Slack apps use [OAuth to manage access to Slack's APIs](https://docs.slack.dev/authentication/installing-with-oauth). When an app is installed, you'll receive a token that the app can use to call API methods. + +There are three main token types available to a Slack app: user (`xoxp`), bot (`xoxb`), and app-level (`xapp`) tokens. +- [User tokens](https://docs.slack.dev/authentication/tokens#user) allow you to call API methods on behalf of users after they install or authenticate the app. There may be several user tokens for a single workspace. +- [Bot tokens](https://docs.slack.dev/authentication/tokens#bot) are associated with bot users, and are only granted once in a workspace where someone installs the app. The bot token your app uses will be the same no matter which user performed the installation. Bot tokens are the token type that _most_ apps use. +- [App-level tokens](https://docs.slack.dev/authentication/tokens#app-level) represent your app across organizations, including installations by all individual users on all workspaces in a given organization and are commonly used for creating WebSocket connections to your app. + +We're going to use bot and app-level tokens for this guide. + +1. Navigate to **OAuth & Permissions** on the left sidebar and scroll down to the **Bot Token Scopes** section. Click **Add an OAuth Scope**. + +2. For now, we'll just add one scope: [`chat:write`](https://docs.slack.dev/reference/scopes/chat.write). This grants your app the permission to post messages in channels it's a member of. + +3. Scroll up to the top of the **OAuth & Permissions** page and click **Install App to Workspace**. You'll be led through Slack's OAuth UI, where you should allow your app to be installed to your development workspace. + +4. Once you authorize the installation, you'll land on the **OAuth & Permissions** page and see a **Bot User OAuth Access Token**. + +![OAuth Tokens](/img/boltpy/bot-token.png "Bot OAuth Token") + +5. Head over to **Basic Information** and scroll down under the App Token section and click **Generate Token and Scopes** to generate an app-level token. Add the `connections:write` scope to this token and save the generated `xapp` token. + +6. Navigate to **Socket Mode** on the left side menu and toggle to enable. + +:::tip[Not sharing is sometimes caring] + +Treat your tokens like passwords and [keep them safe](https://docs.slack.dev/authentication/best-practices-for-security). Your app uses tokens to post and retrieve information from Slack workspaces. + +::: + +--- + +### Setting up your project {#setting-up-your-project} + +With the initial configuration handled, it's time to set up a new Bolt project. This is where you'll write the code that handles the logic for your app. + +If you don’t already have a project, let’s create a new one. Create an empty directory: + +```sh +$ mkdir first-bolt-app +$ cd first-bolt-app +``` + +Next, we recommend using a [Python virtual environment](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment) to manage your project's dependencies. This is a great way to prevent conflicts with your system's Python packages. Let's create and activate a new virtual environment with [Python 3.6 or later](https://www.python.org/downloads/): + +```sh +$ python3 -m venv .venv +$ source .venv/bin/activate +$ pip install -r requirements.txt +``` + +We can confirm that the virtual environment is active by checking that the path to `python3` is _inside_ your project ([a similar command is available on Windows](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#activating-a-virtual-environment)): + +```sh +$ which python3 +# Output: /path/to/first-bolt-app/.venv/bin/python3 +``` + +Before we install the Bolt for Python package to your new project, let's save the **bot token** and **app-level token** that were generated when you configured your app. + +1. **Copy your bot (xoxb) token from the OAuth & Permissions page** and store it in a new environment variable. The following example works on Linux and macOS; but [similar commands are available on Windows](https://superuser.com/questions/212150/how-to-set-env-variable-in-windows-cmd-line/212153#212153). + +```sh +$ export SLACK_BOT_TOKEN=xoxb- +``` + +2. **Copy your app-level (xapp) token from the Basic Information page** and then store it in a new environment variable. + +```sh +$ export SLACK_APP_TOKEN= +``` + +:::warning[Keep it secret. Keep it safe.] + +Remember to keep your tokens secure. At a minimum, you should avoid checking them into public version control, and access them via environment variables as we've done above. Check out the API documentation for more on [best practices for app security](https://docs.slack.dev/authentication/best-practices-for-security). + +::: + +Now, let's create your app. Install the `slack_bolt` Python package to your virtual environment using the following command: + +```sh +$ pip install slack_bolt +``` + +Create a new file called `app.py` in this directory and add the following code: + +```python +import os +from slack_bolt import App +from slack_bolt.adapter.socket_mode import SocketModeHandler + +# Initializes your app with your bot token and socket mode handler +app = App(token=os.environ.get("SLACK_BOT_TOKEN")) + +# Start your app +if __name__ == "__main__": + SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start() +``` + +Your tokens are enough to create your first Bolt app. Save your `app.py` file then on the command line run the following: + +```sh +$ python3 app.py +``` + +Your app should let you know that it's up and running. 🎉 + +--- + +### Setting up events {#setting-up-events} +Your app behaves similarly to people on your team — it can post messages, add emoji reactions, and listen and respond to events. + +To listen for events happening in a Slack workspace (like when a message is posted or when a reaction is posted to a message) you'll use the [Events API to subscribe to event types](https://docs.slack.dev/apis/events-api/). + +For those just starting, we recommend using [Socket Mode](https://docs.slack.dev/apis/events-api/using-socket-mode). Socket Mode allows your app to use the Events API and interactive features without exposing a public HTTP Request URL. This can be helpful during development, or if you're receiving requests from behind a firewall. + +That being said, you're welcome to set up an app with a public HTTP Request URL. HTTP is more useful for apps being deployed to hosting environments to respond within a large corporate Slack workspaces/organization, or apps intended for distribution via the Slack Marketplace. + +We've provided instructions for both ways in this guide. + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + + + + +1. Head to your app's configuration page (click on the app [from your app settings page](https://api.slack.com/apps)). Navigate to **Socket Mode** on the left side menu and toggle to enable. + +2. Go to **Basic Information** and scroll down under the App-Level Tokens section and click **Generate Token and Scopes** to generate an app-level token. Add the `connections:write` scope to this token and save the generated `xapp` token, we'll use that in just a moment. + +3. Finally, it's time to tell Slack what events we'd like to listen for. Under **Event Subscriptions**, toggle the switch labeled **Enable Events**. + +When an event occurs, Slack will send your app some information about the event, like the user that triggered it and the channel it occurred in. Your app will process the details and can respond accordingly. + + + + +1. Go back to your app configuration page (click on the app [from your app management page](https://api.slack.com/apps)). Click **Event Subscriptions** on the left sidebar. Toggle the switch labeled **Enable Events**. + +2. Add your Request URL. Slack will send HTTP POST requests corresponding to events to this [Request URL](https://docs.slack.dev/apis/events-api/#subscribing) endpoint. Bolt uses the `/slack/events` path to listen to all incoming requests (whether shortcuts, events, or interactivity payloads). When configuring your Request URL within your app configuration, you'll append `/slack/events`, e.g. `https:///slack/events`. 💡 As long as your Bolt app is still running, your URL should become verified. + +:::tip[Using proxy services] + +For local development, you can use a proxy service like ngrok to create a public URL and tunnel requests to your development environment. Refer to [ngrok's getting started guide](https://ngrok.com/docs#getting-started-expose) on how to create this tunnel. And when you get to hosting your app, we've collected some of the most common hosting providers Slack developers use to host their apps [on our API site](https://docs.slack.dev/distribution/hosting-slack-apps/). + +::: + + + + +Navigate to **Event Subscriptions** on the left sidebar and toggle to enable. Under **Subscribe to Bot Events**, you can add events for your bot to respond to. There are four events related to messages: +- [`message.channels`](https://docs.slack.dev/reference/events/message.channels) listens for messages in public channels that your app is added to. +- [`message.groups`](https://docs.slack.dev/reference/events/message.groups) listens for messages in 🔒 private channels that your app is added to. +- [`message.im`](https://docs.slack.dev/reference/events/message.im) listens for messages in your app's DMs with users. +- [`message.mpim`](https://docs.slack.dev/reference/events/message.mpim) listens for messages in multi-person DMs that your app is added to. + +If you want your bot to listen to messages from everywhere it is added to, choose all four message events. After you’ve selected the events you want your bot to listen to, click the green **Save Changes** button. + +--- + +### Listening and responding to a message {#listening-and-responding-to-a-message} +Your app is now ready for some logic. Let's start by using the `message()` method to attach a listener for messages. + +The following example listens and responds to all messages in channels/DMs where your app has been added that contain the word "hello": + + + + +```python +import os +from slack_bolt import App +from slack_bolt.adapter.socket_mode import SocketModeHandler + +# Initializes your app with your bot token and socket mode handler +app = App(token=os.environ.get("SLACK_BOT_TOKEN")) + +# Listens to incoming messages that contain "hello" +# To learn available listener arguments, +# visit https://tools.slack.dev/bolt-python/api-docs/slack_bolt/kwargs_injection/args.html +@app.message("hello") +def message_hello(message, say): + # say() sends a message to the channel where the event was triggered + say(f"Hey there <@{message['user']}>!") + +# Start your app +if __name__ == "__main__": + SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start() +``` + + + + +```python +import os +from slack_bolt import App + +# Initializes your app with your bot token and signing secret +app = App( + token=os.environ.get("SLACK_BOT_TOKEN"), + signing_secret=os.environ.get("SLACK_SIGNING_SECRET") +) + +# Listens to incoming messages that contain "hello" +# To learn available listener arguments, +# visit https://tools.slack.dev/bolt-python/api-docs/slack_bolt/kwargs_injection/args.html +@app.message("hello") +def message_hello(message, say): + # say() sends a message to the channel where the event was triggered + say(f"Hey there <@{message['user']}>!") + +# Start your app +if __name__ == "__main__": + app.start(port=int(os.environ.get("PORT", 3000))) +``` + + + + +If you restart your app, so long as your bot user has been added to the channel or DM conversation, when you send any message that contains "hello", it will respond. + +This is a basic example, but it gives you a place to start customizing your app based on your own goals. Let's try something a little more interactive by sending a button rather than plain text. + +--- + +### Sending and responding to actions {#sending-and-responding-to-actions} + +To use features like buttons, select menus, datepickers, modals, and shortcuts, you’ll need to enable interactivity. Head over to **Interactivity & Shortcuts** in your app configuration. + + + + +With Socket Mode on, basic interactivity is enabled by default, so no further action is needed. + + + + +Similar to events, you'll need to specify a URL for Slack to send the action (such as _user clicked a button_). Back on your app configuration page, click on **Interactivity & Shortcuts** on the left side. You'll see that there's another **Request URL** box. + +:::tip + +By default, Bolt is configured to use the same endpoint for interactive components that it uses for events, so use the same request URL as above (for example, `https://8e8ec2d7.ngrok.io/slack/events`). Press the **Save Changes** button in the lower right hand corner, and that's it. Your app is set up to handle interactivity! + +::: + + + + +When interactivity is enabled, interactions with shortcuts, modals, or interactive components (such as buttons, select menus, and datepickers) will be sent to your app as events. + +Now, let's go back to your app's code and add logic to handle those events: +- First, we'll send a message that contains an interactive component (in this case a button). +- Next, we'll listen for the action of a user clicking the button before responding. + +Below, the code from the last section is modified to send a message containing a button rather than just a string: + + + + +```python +import os +from slack_bolt import App +from slack_bolt.adapter.socket_mode import SocketModeHandler + +# Initializes your app with your bot token and socket mode handler +app = App( + token=os.environ.get("SLACK_BOT_TOKEN"), + # signing_secret=os.environ.get("SLACK_SIGNING_SECRET") # not required for socket mode +) + +# Listens to incoming messages that contain "hello" +@app.message("hello") +def message_hello(message, say): + # say() sends a message to the channel where the event was triggered + say( + blocks=[ + { + "type": "section", + "text": {"type": "mrkdwn", "text": f"Hey there <@{message['user']}>!"}, + "accessory": { + "type": "button", + "text": {"type": "plain_text", "text": "Click Me"}, + "action_id": "button_click" + } + } + ], + text=f"Hey there <@{message['user']}>!" + ) + +# Start your app +if __name__ == "__main__": + SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start() + +``` + + + + +```python +import os +from slack_bolt import App + +# Initializes your app with your bot token and signing secret +app = App( + token=os.environ.get("SLACK_BOT_TOKEN"), + signing_secret=os.environ.get("SLACK_SIGNING_SECRET") +) + +# Listens to incoming messages that contain "hello" +@app.message("hello") +def message_hello(message, say): + # say() sends a message to the channel where the event was triggered + say( + blocks=[ + { + "type": "section", + "text": {"type": "mrkdwn", "text": f"Hey there <@{message['user']}>!"}, + "accessory": { + "type": "button", + "text": {"type": "plain_text", "text": "Click Me"}, + "action_id": "button_click" + } + } + ], + text=f"Hey there <@{message['user']}>!" + ) + +# Start your app +if __name__ == "__main__": + app.start(port=int(os.environ.get("PORT", 3000))) +``` + + + + +The value inside of `say()` is now an object that contains an array of `blocks`. Blocks are the building components of a Slack message and can range from text to images to datepickers. In this case, your app will respond with a section block that includes a button as an accessory. Since we're using `blocks`, the `text` is a fallback for notifications and accessibility. + +You'll notice in the button `accessory` object, there is an `action_id`. This will act as a unique identifier for the button so your app can specify which action it wants to respond to. + +:::tip[Using Block Kit Builder] + +The [Block Kit Builder](https://app.slack.com/block-kit-builder) is an simple way to prototype your interactive messages. The builder lets you (or anyone on your team) mock up messages and generates the corresponding JSON that you can paste directly in your app. + +::: + +Now, if you restart your app and say "hello" in a channel your app is in, you'll see a message with a button. But if you click the button, nothing happens (_yet!_). + +Let's add a handler to send a follow-up message when someone clicks the button: + + + + +```python +import os +from slack_bolt import App +from slack_bolt.adapter.socket_mode import SocketModeHandler + +# Initializes your app with your bot token and socket mode handler +app = App(token=os.environ.get("SLACK_BOT_TOKEN")) + +# Listens to incoming messages that contain "hello" +@app.message("hello") +def message_hello(message, say): + # say() sends a message to the channel where the event was triggered + say( + blocks=[ + { + "type": "section", + "text": {"type": "mrkdwn", "text": f"Hey there <@{message['user']}>!"}, + "accessory": { + "type": "button", + "text": {"type": "plain_text", "text": "Click Me"}, + "action_id": "button_click" + } + } + ], + text=f"Hey there <@{message['user']}>!" + ) + +@app.action("button_click") +def action_button_click(body, ack, say): + # Acknowledge the action + ack() + say(f"<@{body['user']['id']}> clicked the button") + +# Start your app +if __name__ == "__main__": + SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start() +``` + + + + +```python +import os +from slack_bolt import App + +# Initializes your app with your bot token and signing secret +app = App( + token=os.environ.get("SLACK_BOT_TOKEN"), + signing_secret=os.environ.get("SLACK_SIGNING_SECRET") +) + +# Listens to incoming messages that contain "hello" +@app.message("hello") +def message_hello(message, say): + # say() sends a message to the channel where the event was triggered + say( + blocks=[ + { + "type": "section", + "text": {"type": "mrkdwn", "text": f"Hey there <@{message['user']}>!"}, + "accessory": { + "type": "button", + "text": {"type": "plain_text", "text": "Click Me"}, + "action_id": "button_click" + } + } + ], + text=f"Hey there <@{message['user']}>!" + ) + +@app.action("button_click") +def action_button_click(body, ack, say): + # Acknowledge the action + ack() + say(f"<@{body['user']['id']}> clicked the button") + +# Start your app +if __name__ == "__main__": + app.start(port=int(os.environ.get("PORT", 3000))) +``` + + + + +You can see that we used `app.action()` to listen for the `action_id` that we named `button_click`. If you restart your app and click the button, you'll see a new message from your app that says you clicked the button. + +--- + +### Next steps {#next-steps} +You just built your first [Bolt for Python app](https://github.com/slackapi/bolt-python/tree/main/examples/getting_started)! 🎉 + +Now that you have a basic app up and running, you can start exploring how to make your Bolt app stand out. Here are some ideas about what to explore next: + +* Read through the concepts pages to learn about the different methods and features your Bolt app has access to. + +* Explore the different events your bot can listen to with the [`app.event()`](/concepts/event-listening) method. All of the events are listed [on the API docs site](https://docs.slack.dev/reference/events). + +* Bolt allows you to [call Web API methods](/concepts/web-api) with the client attached to your app. There are [over 200 methods](https://docs.slack.dev/reference/methods) on our API site. + +* Learn more about the different token types [on the API docs site](https://docs.slack.dev/authentication/tokens). Your app may need different tokens depending on the actions you want it to perform. diff --git a/docs/content/getting-started.md b/docs/content/getting-started.md index d1b7d5e2c..a794f3176 100644 --- a/docs/content/getting-started.md +++ b/docs/content/getting-started.md @@ -1,481 +1,300 @@ --- -title: Getting Started -slug: getting-started -lang: en +title: Quickstart guide with Bolt for Python +sidebar_label: Quickstart --- # Getting started with Bolt for Python -This guide is meant to walk you through getting up and running with a Slack app using Bolt for Python. Along the way, we’ll create a new Slack app, set up your local environment, and develop an app that listens and responds to messages from a Slack workspace. +This quickstart guide aims to help you get a Slack app using Bolt for Python up and running as soon as possible! -When you're finished, you'll have this ⚡️[Getting Started with Slack app](https://github.com/slackapi/bolt-python/tree/main/examples/getting_started) to run, modify, and make your own. - ---- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; -### Create an app {#create-an-app} -First thing's first: before you start developing with Bolt, you'll want to [create a Slack app](https://api.slack.com/apps/new). +When complete, you'll have a local environment configured with a customized [app](https://github.com/slack-samples/bolt-python-getting-started-app) running to modify and make your own. -:::tip +:::tip[Reference for readers] -We recommend using a workspace where you won't disrupt real work getting done — [you can create a new one for free](https://slack.com/get-started#create). +In search of the complete guide to building an app from scratch? Check out the [building an app](/building-an-app) guide. ::: -After you fill out an app name (_you can change it later_) and pick a workspace to install it to, hit the `Create App` button and you'll land on your app's **Basic Information** page. +#### Prerequisites -This page contains an overview of your app in addition to important credentials you'll need later. +A few tools are needed for the following steps. We recommend using the [**Slack CLI**](https://tools.slack.dev/slack-cli/) for the smoothest experience, but other options remain available. -![Basic Information page](/img/boltpy/basic-information-page.png "Basic Information page") +You can also begin by installing git and downloading [Python 3.6 or later](https://www.python.org/downloads/), or the latest stable version of Python. Refer to [Python's setup and building guide](https://devguide.python.org/getting-started/setup-building/) for more details. -Look around, add an app icon and description, and then let's start configuring your app 🔩 +Install the latest version of the Slack CLI to get started: ---- +- [Slack CLI for macOS & Linux](https://tools.slack.dev/slack-cli/guides/installing-the-slack-cli-for-mac-and-linux) +- [Slack CLI for Windows](https://tools.slack.dev/slack-cli/guides/installing-the-slack-cli-for-windows) -### Tokens and installing apps {#tokens-and-installing-apps} -Slack apps use [OAuth to manage access to Slack's APIs](https://docs.slack.dev/authentication/installing-with-oauth). When an app is installed, you'll receive a token that the app can use to call API methods. +Then confirm a successful installation with the following command: -There are three main token types available to a Slack app: user (`xoxp`), bot (`xoxb`), and app-level (`xapp`) tokens. -- [User tokens](https://docs.slack.dev/authentication/tokens#user) allow you to call API methods on behalf of users after they install or authenticate the app. There may be several user tokens for a single workspace. -- [Bot tokens](https://docs.slack.dev/authentication/tokens#bot) are associated with bot users, and are only granted once in a workspace where someone installs the app. The bot token your app uses will be the same no matter which user performed the installation. Bot tokens are the token type that _most_ apps use. -- [App-level tokens](https://docs.slack.dev/authentication/tokens#app-level) represent your app across organizations, including installations by all individual users on all workspaces in a given organization and are commonly used for creating WebSocket connections to your app. +```sh +$ slack version +``` -We're going to use bot and app-level tokens for this guide. +An authenticated login is also required if this hasn't been done before: -1. Navigate to the **OAuth & Permissions** on the left sidebar and scroll down to the **Bot Token Scopes** section. Click **Add an OAuth Scope**. +```sh +$ slack login +``` -2. For now, we'll just add one scope: [`chat:write`](https://docs.slack.dev/reference/scopes/chat.write). This grants your app the permission to post messages in channels it's a member of. +:::info[A place to belong] -3. Scroll up to the top of the **OAuth & Permissions** page and click **Install App to Workspace**. You'll be led through Slack's OAuth UI, where you should allow your app to be installed to your development workspace. +A workspace where development can happen is also needed. -4. Once you authorize the installation, you'll land on the **OAuth & Permissions** page and see a **Bot User OAuth Access Token**. +We recommend using [developer sandboxes](https://docs.slack.dev/tools/developer-sandboxes) to avoid disruptions where real work gets done. -![OAuth Tokens](/img/boltpy/bot-token.png "Bot OAuth Token") +::: -5. Then head over to **Basic Information** and scroll down under the App Token section and click **Generate Token and Scopes** to generate an app-level token. Add the `connections:write` scope to this token and save the generated `xapp` token, we'll use both these tokens in just a moment. +## Creating a project {#creating-a-project} -6. Navigate to **Socket Mode** on the left side menu and toggle to enable. +With the toolchain configured, it's time to set up a new Bolt project. This contains the code that handles logic for your app. -:::tip +If you don’t already have a project, let’s create a new one! -Treat your tokens like passwords and [keep them safe](https://docs.slack.dev/authentication/best-practices-for-security). Your app uses tokens to post and retrieve information from Slack workspaces. + + -::: +A starter template can be used to start with project scaffolding: ---- - -### Setting up your project {#setting-up-your-project} +```sh +$ slack create first-bolt-app --template slack-samples/bolt-python-getting-started-app +$ cd first-bolt-app +``` -With the initial configuration handled, it's time to set up a new Bolt project. This is where you'll write the code that handles the logic for your app. +After a project is created you'll have a `requirements.txt` file for app dependencies and a `.slack` directory for Slack CLI configuration. -If you don’t already have a project, let’s create a new one. Create an empty directory: +A few other files exist too, but we'll visit these later. -```shell -mkdir first-bolt-app -cd first-bolt-app -``` + + -Next, we recommend using a [Python virtual environment](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment) to manage your project's dependencies. This is a great way to prevent conflicts with your system's Python packages. Let's create and activate a new virtual environment with [Python 3.6 or later](https://www.python.org/downloads/): +A starter template can be cloned to start with project scaffolding: -```shell -python3 -m venv .venv -source .venv/bin/activate +```sh +$ git clone https://github.com/slack-samples/bolt-python-getting-started-app first-bolt-app +$ cd first-bolt-app ``` -We can confirm that the virtual environment is active by checking that the path to `python3` is _inside_ your project ([a similar command is available on Windows](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#activating-a-virtual-environment)): +Outlines of a project are taking shape, so we can move on to running the app! -```shell -which python3 -# Output: /path/to/first-bolt-app/.venv/bin/python3 -``` + + -Before we install the Bolt for Python package to your new project, let's save the **bot token** and **app-level token** that were generated when you configured your app. +We recommend using a [Python virtual environment](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment) to manage your project's dependencies. This is a great way to prevent conflicts with your system's Python packages. Let's create and activate a new virtual environment with [Python 3.6 or later](https://www.python.org/downloads/): -1. **Copy your bot (xoxb) token from the OAuth & Permissions page** and store it in a new environment variable. The following example works on Linux and macOS; but [similar commands are available on Windows](https://superuser.com/questions/212150/how-to-set-env-variable-in-windows-cmd-line/212153#212153). -```shell -export SLACK_BOT_TOKEN=xoxb- +```sh +$ python3 -m venv .venv +$ source .venv/bin/activate +$ pip install -r requirements.txt ``` -2. **Copy your app-level (xapp) token from the Basic Information page** and then store it in a new environment variable. -```shell -export SLACK_APP_TOKEN= +Confirm the virtual environment is active by checking that the path to `python3` is _inside_ your project ([a similar command is available on Windows](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#activating-a-virtual-environment)): + +```sh +$ which python3 +# Output: /path/to/first-bolt-app/.venv/bin/python3 ``` -:::warning +## Running the app {#running-the-app} -Remember to keep your tokens secure. At a minimum, you should avoid checking them into public version control, and access them via environment variables as we've done above. Check out the API documentation for more on [best practices for app security](https://docs.slack.dev/authentication/best-practices-for-security). +Before you can start developing with Bolt, you will want a running Slack app. -::: + + -Now, let's create your app. Install the `slack_bolt` Python package to your virtual environment using the following command: +The getting started app template contains a `manifest.json` file with details about an app that we will use to get started. Use the following command and select "Create a new app" to install the app to the team of choice: -```shell -pip install slack_bolt +```sh +$ slack run +... +⚡️ Bolt app is running! ``` -Create a new file called `app.py` in this directory and add the following code: +With the app running, you can test it out with the following steps in Slack: -```python -import os -from slack_bolt import App -from slack_bolt.adapter.socket_mode import SocketModeHandler +1. Open a direct message with your app or invite the bot `@first-bolt-app (local)` to a public channel. +2. Send "hello" to the current conversation and wait for a response. +3. Click the attached button labelled "Click Me" to post another reply. -# Initializes your app with your bot token and socket mode handler -app = App(token=os.environ.get("SLACK_BOT_TOKEN")) +After confirming the app responds, celebrate, then interrupt the process by pressing `CTRL+C` in the terminal to stop your app from running. -# Start your app -if __name__ == "__main__": - SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start() -``` + + -Your tokens are enough to create your first Bolt app. Save your `app.py` file then on the command line run the following: +Navigate to your list of apps and [create a new Slack app](https://api.slack.com/apps/new) using the "from a manifest" option: -```script -python3 app.py -``` +1. Select the workspace to develop your app in. +2. Copy and paste the `manifest.json` file contents to create your app. +3. Confirm the app features and click "Create". -Your app should let you know that it's up and running. 🎉 +You'll then land on your app's **Basic Information** page, which is an overview of your app and which contains important credentials: ---- +![Basic Information page](/img/boltpy/basic-information-page.png "Basic Information page") -### Setting up events {#setting-up-events} -Your app behaves similarly to people on your team — it can post messages, add emoji reactions, and listen and respond to events. +To listen for events happening in Slack (such as a new posted message) without opening a port or exposing an endpoint, we will use [Socket Mode](/concepts/socket-mode). This connection requires a specific app token: -To listen for events happening in a Slack workspace (like when a message is posted or when a reaction is posted to a message) you'll use the [Events API to subscribe to event types](https://docs.slack.dev/apis/events-api/). +1. On the **Basic Information** page, scroll to the **App-Level Tokens** section and click **Generate Token and Scopes**. +2. Name the token "Development" or something similar and add the `connections:write` scope, then click **Generate**. +3. Save the generated `xapp` token as an environment variable within your project: -For those just starting, we recommend using [Socket Mode](https://docs.slack.dev/apis/events-api/using-socket-mode). Socket Mode allows your app to use the Events API and interactive features without exposing a public HTTP Request URL. This can be helpful during development, or if you're receiving requests from behind a firewall. +```sh +$ export SLACK_APP_TOKEN= +``` -That being said, you're welcome to set up an app with a public HTTP Request URL. HTTP is more useful for apps being deployed to hosting environments to respond within a large corporate Slack workspaces/organization, or apps intended for distribution via the Slack Marketplace. +The above command works on Linux and macOS but [similar commands are available on Windows](https://superuser.com/questions/212150/how-to-set-env-variable-in-windows-cmd-line/212153#212153). -We've provided instructions for both ways in this guide. +:::warning[Keep it secret. Keep it safe.] -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; +Treat your tokens like a password and [keep it safe](https://docs.slack.dev/authentication/best-practices-for-security). Your app uses these to retrieve and send information to Slack. - - +::: -1. Head to your app's configuration page (click on the app [from your app settings page](https://api.slack.com/apps)). Navigate to **Socket Mode** on the left side menu and toggle to enable. +A bot token is also needed to interact with the Web API methods as your app's bot user. We can gather this as follows: -2. Go to **Basic Information** and scroll down under the App-Level Tokens section and click **Generate Token and Scopes** to generate an app token. Add the `connections:write` scope to this token and save the generated `xapp` token, we'll use that in just a moment. +1. Navigate to the **OAuth & Permissions** on the left sidebar and install your app to your workspace to generate a token. +2. After authorizing the installation, you'll return to the **OAuth & Permissions** page and find a **Bot User OAuth Token**: -3. Finally, it's time to tell Slack what events we'd like to listen for. Under **Event Subscriptions**, toggle the switch labeled **Enable Events**. +![OAuth Tokens](/img/boltpy/bot-token.png "Bot OAuth Token") -When an event occurs, Slack will send your app some information about the event, like the user that triggered it and the channel it occurred in. Your app will process the details and can respond accordingly. +3. Copy the bot token beginning with `xoxb` from the **OAuth & Permissions page** and then store it in a new environment variable: - - +```sh +$ export SLACK_BOT_TOKEN=xoxb- +``` -1. Go back to your app configuration page (click on the app [from your app management page](https://api.slack.com/apps)). Click **Event Subscriptions** on the left sidebar. Toggle the switch labeled **Enable Events**. +After saving tokens for the app you created, it is time to run it: -2. Add your Request URL. Slack will send HTTP POST requests corresponding to events to this [Request URL](https://docs.slack.dev/apis/events-api/#subscribing) endpoint. Bolt uses the `/slack/events` path to listen to all incoming requests (whether shortcuts, events, or interactivity payloads). When configuring your Request URL within your app configuration, you'll append `/slack/events`, e.g. `https:///slack/events`. 💡 As long as your Bolt app is still running, your URL should become verified. +```sh +$ python3 app.py +... +⚡️ Bolt app is running! +``` -:::tip +With the app running, you can test it out with the following steps in Slack: -For local development, you can use a proxy service like ngrok to create a public URL and tunnel requests to your development environment. Refer to [ngrok's getting started guide](https://ngrok.com/docs#getting-started-expose) on how to create this tunnel. And when you get to hosting your app, we've collected some of the most common hosting providers Slack developers use to host their apps [on our API site](https://docs.slack.dev/distribution/hosting-slack-apps/). +1. Open a direct message with your app or invite the bot `@BoltApp` to a public channel. +2. Send "hello" to the current conversation and wait for a response. +3. Click the attached button labelled "Click Me" to post another reply. -::: +After confirming the app responds, celebrate, then interrupt the process by pressing `CTRL+C` in the terminal to stop your app from running. -Navigate to **Event Subscriptions** on the left sidebar and toggle to enable. Under **Subscribe to Bot Events**, you can add events for your bot to respond to. There are four events related to messages: -- [`message.channels`](https://docs.slack.dev/reference/events/message.channels) listens for messages in public channels that your app is added to -- [`message.groups`](https://docs.slack.dev/reference/events/message.groups) listens for messages in 🔒 private channels that your app is added to -- [`message.im`](https://docs.slack.dev/reference/events/message.im) listens for messages in your app's DMs with users -- [`message.mpim`](https://docs.slack.dev/reference/events/message.mpim) listens for messages in multi-person DMs that your app is added to +## Updating the app -If you want your bot to listen to messages from everywhere it is added to, choose all four message events. After you’ve selected the events you want your bot to listen to, click the green **Save Changes** button. +At this point, you've successfully run the getting started Bolt for Python [app](https://github.com/slack-samples/bolt-python-getting-started-app)! ---- +The defaults included leave opportunities abound, so to personalize this app let's now edit the code to respond with a kind farewell. -### Listening and responding to a message {#listening-and-responding-to-a-message} -Your app is now ready for some logic. Let's start by using the `message()` method to attach a listener for messages. +#### Responding to a farewell -The following example listens and responds to all messages in channels/DMs where your app has been added that contain the word "hello": +Chat is a common thing apps do and responding to various types of messages can make conversations more interesting. - - +Using an editor of choice, open the `app.py` file and add the following import to the top of the file, and message listener after the "hello" handler: ```python -import os -from slack_bolt import App -from slack_bolt.adapter.socket_mode import SocketModeHandler - -# Initializes your app with your bot token and socket mode handler -app = App(token=os.environ.get("SLACK_BOT_TOKEN")) - -# Listens to incoming messages that contain "hello" -# To learn available listener arguments, -# visit https://tools.slack.dev/bolt-python/api-docs/slack_bolt/kwargs_injection/args.html -@app.message("hello") -def message_hello(message, say): - # say() sends a message to the channel where the event was triggered - say(f"Hey there <@{message['user']}>!") - -# Start your app -if __name__ == "__main__": - SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start() -``` - - - +import random -```python -import os -from slack_bolt import App - -# Initializes your app with your bot token and signing secret -app = App( - token=os.environ.get("SLACK_BOT_TOKEN"), - signing_secret=os.environ.get("SLACK_SIGNING_SECRET") -) - -# Listens to incoming messages that contain "hello" -# To learn available listener arguments, -# visit https://tools.slack.dev/bolt-python/api-docs/slack_bolt/kwargs_injection/args.html -@app.message("hello") -def message_hello(message, say): - # say() sends a message to the channel where the event was triggered - say(f"Hey there <@{message['user']}>!") - -# Start your app -if __name__ == "__main__": - app.start(port=int(os.environ.get("PORT", 3000))) +@app.message("goodbye") +def message_goodbye(say): + responses = ["Adios", "Au revoir", "Farewell"] + parting = random.choice(responses) + say(f"{parting}!") ``` - - - -If you restart your app, so long as your bot user has been added to the channel/DM, when you send any message that contains "hello", it will respond. +Once the file is updated, save the changes and then we'll make sure those changes are being used. -This is a basic example, but it gives you a place to start customizing your app based on your own goals. Let's try something a little more interactive by sending a button rather than plain text. + + ---- +Run the following command and select the app created earlier to start, or restart, your app with the latest changes: -### Sending and responding to actions {#sending-and-responding-to-actions} +```sh +$ slack run +... +⚡️ Bolt app is running! +``` -To use features like buttons, select menus, datepickers, modals, and shortcuts, you’ll need to enable interactivity. Head over to **Interactivity & Shortcuts** in your app configuration. +After finding the above output appears, open Slack to perform these steps: - - +1. Return to the direct message or public channel with your bot. +2. Send "goodbye" to the conversation. +3. Receive a parting response from before and repeat "goodbye" to find another one. -With Socket Mode on, basic interactivity is enabled by default, so no further action is needed. +Your app can be stopped again by pressing `CTRL+C` in the terminal to end these chats. - + -Similar to events, you'll need to specify a URL for Slack to send the action (such as *user clicked a button*). Back on your app configuration page, click on **Interactivity & Shortcuts** on the left side. You'll see that there's another **Request URL** box. +Run the following command to start, or restart, your app with the latest changes: -:::tip +```sh +$ python3 app.py +... +⚡️ Bolt app is running! +``` -By default, Bolt is configured to use the same endpoint for interactive components that it uses for events, so use the same request URL as above (for example, `https://8e8ec2d7.ngrok.io/slack/events`). Press the **Save Changes** button in the lower right hand corner, and that's it. Your app is set up to handle interactivity! +After finding the above output appears, open Slack to perform these steps: -::: +1. Return to the direct message or public channel with your bot. +2. Send "goodbye" to the conversation. +3. Receive a parting response from before and repeat "goodbye" to find another one. + +Your app can be stopped again by pressing `CTRL+C` in the terminal to end these chats. -When interactivity is enabled, interactions with shortcuts, modals, or interactive components (such as buttons, select menus, and datepickers) will be sent to your app as events. +#### Customizing app settings -Now, let's go back to your app's code and add logic to handle those events: -- First, we'll send a message that contains an interactive component (in this case a button) -- Next, we'll listen for the action of a user clicking the button before responding +The created app will have some placeholder values and a small set of [scopes](https://docs.slack.dev/reference/scopes) to start, but we recommend exploring the customizations possible on app settings. -Below, the code from the last section is modified to send a message containing a button rather than just a string: + + - - - -```python -import os -from slack_bolt import App -from slack_bolt.adapter.socket_mode import SocketModeHandler - -# Initializes your app with your bot token and socket mode handler -app = App( - token=os.environ.get("SLACK_BOT_TOKEN"), - # signing_secret=os.environ.get("SLACK_SIGNING_SECRET") # not required for socket mode -) - -# Listens to incoming messages that contain "hello" -@app.message("hello") -def message_hello(message, say): - # say() sends a message to the channel where the event was triggered - say( - blocks=[ - { - "type": "section", - "text": {"type": "mrkdwn", "text": f"Hey there <@{message['user']}>!"}, - "accessory": { - "type": "button", - "text": {"type": "plain_text", "text": "Click Me"}, - "action_id": "button_click" - } - } - ], - text=f"Hey there <@{message['user']}>!" - ) - -# Start your app -if __name__ == "__main__": - SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start() +Open app settings for your app with the following command: +```sh +$ slack app settings ``` - - +This will open the following page in a web browser: -```python -import os -from slack_bolt import App - -# Initializes your app with your bot token and signing secret -app = App( - token=os.environ.get("SLACK_BOT_TOKEN"), - signing_secret=os.environ.get("SLACK_SIGNING_SECRET") -) - -# Listens to incoming messages that contain "hello" -@app.message("hello") -def message_hello(message, say): - # say() sends a message to the channel where the event was triggered - say( - blocks=[ - { - "type": "section", - "text": {"type": "mrkdwn", "text": f"Hey there <@{message['user']}>!"}, - "accessory": { - "type": "button", - "text": {"type": "plain_text", "text": "Click Me"}, - "action_id": "button_click" - } - } - ], - text=f"Hey there <@{message['user']}>!" - ) - -# Start your app -if __name__ == "__main__": - app.start(port=int(os.environ.get("PORT", 3000))) -``` +![Basic Information page](/img/boltpy/basic-information-page.png "Basic Information page") - - -The value inside of `say()` is now an object that contains an array of `blocks`. Blocks are the building components of a Slack message and can range from text to images to datepickers. In this case, your app will respond with a section block that includes a button as an accessory. Since we're using `blocks`, the `text` is a fallback for notifications and accessibility. - -You'll notice in the button `accessory` object, there is an `action_id`. This will act as a unique identifier for the button so your app can specify what action it wants to respond to. - -:::tip - -The [Block Kit Builder](https://app.slack.com/block-kit-builder) is an simple way to prototype your interactive messages. The builder lets you (or anyone on your team) mockup messages and generates the corresponding JSON that you can paste directly in your app. - -::: - -Now, if you restart your app and say "hello" in a channel your app is in, you'll see a message with a button. But if you click the button, nothing happens (*yet!*). - -Let's add a handler to send a followup message when someone clicks the button: + - - +Browse to https://api.slack.com/apps and select your app "Getting Started Bolt App" from the list. -```python -import os -from slack_bolt import App -from slack_bolt.adapter.socket_mode import SocketModeHandler - -# Initializes your app with your bot token and socket mode handler -app = App(token=os.environ.get("SLACK_BOT_TOKEN")) - -# Listens to incoming messages that contain "hello" -@app.message("hello") -def message_hello(message, say): - # say() sends a message to the channel where the event was triggered - say( - blocks=[ - { - "type": "section", - "text": {"type": "mrkdwn", "text": f"Hey there <@{message['user']}>!"}, - "accessory": { - "type": "button", - "text": {"type": "plain_text", "text": "Click Me"}, - "action_id": "button_click" - } - } - ], - text=f"Hey there <@{message['user']}>!" - ) - -@app.action("button_click") -def action_button_click(body, ack, say): - # Acknowledge the action - ack() - say(f"<@{body['user']['id']}> clicked the button") - -# Start your app -if __name__ == "__main__": - SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start() -``` +This will open the following page: - - - -```python -import os -from slack_bolt import App - -# Initializes your app with your bot token and signing secret -app = App( - token=os.environ.get("SLACK_BOT_TOKEN"), - signing_secret=os.environ.get("SLACK_SIGNING_SECRET") -) - -# Listens to incoming messages that contain "hello" -@app.message("hello") -def message_hello(message, say): - # say() sends a message to the channel where the event was triggered - say( - blocks=[ - { - "type": "section", - "text": {"type": "mrkdwn", "text": f"Hey there <@{message['user']}>!"}, - "accessory": { - "type": "button", - "text": {"type": "plain_text", "text": "Click Me"}, - "action_id": "button_click" - } - } - ], - text=f"Hey there <@{message['user']}>!" - ) - -@app.action("button_click") -def action_button_click(body, ack, say): - # Acknowledge the action - ack() - say(f"<@{body['user']['id']}> clicked the button") - -# Start your app -if __name__ == "__main__": - app.start(port=int(os.environ.get("PORT", 3000))) -``` +![Basic Information page](/img/boltpy/basic-information-page.png "Basic Information page") -You can see that we used `app.action()` to listen for the `action_id` that we named `button_click`. If you restart your app and click the button, you'll see a new message from your app that says you clicked the button. +On these pages you're free to make changes such as updating your app icon, configuring app features, and perhaps even distributing your app! ---- +## Next steps {#next-steps} -### Next steps {#next-steps} -You just built your first [Bolt for Python app](https://github.com/slackapi/bolt-python/tree/main/examples/getting_started)! 🎉 +Congrats once more on getting up and running with this quick start. -Now that you have a basic app up and running, you can start exploring how to make your Bolt app stand out. Here are some ideas about what to explore next: +:::info[Dive deeper] -* Read through the _Basic concepts_ to learn about the different methods and features your Bolt app has access to. +Follow along with the steps that went into making this app on the [building an app](/building-an-app) guide for an educational overview. -* Explore the different events your bot can listen to with the [`app.event()`](/concepts/event-listening) method. All of the events are listed [on the API site](https://docs.slack.dev/reference/events). +::: -* Bolt allows you to [call Web API methods](/concepts/web-api) with the client attached to your app. There are [over 220 methods](https://docs.slack.dev/reference/methods) on our API site. +You can now continue customizing your app with various features to make it right for whatever job's at hand. Here are some ideas about what to explore next: -* Learn more about the different token types [on our API site](https://docs.slack.dev/authentication/tokens). Your app may need different tokens depending on the actions you want it to perform. +- Explore the different events your bot can listen to with the [`app.event()`](/concepts/event-listening) method. All of the [events](https://docs.slack.dev/reference/events) are listed on the API docs site. +- Bolt allows you to call [Web API](/concepts/web-api) methods with the client attached to your app. There are [over 200 methods](https://docs.slack.dev/reference/methods) on the API docs site. +- Learn more about the different [token types](https://docs.slack.dev/authentication/tokens) and [authentication setups](/concepts/authenticating-oauth). Your app might need different tokens depending on the actions you want to perform or for installations to multiple workspaces. +- Receive events using HTTP for various deployment methods, such as deploying to [Heroku](/deployments/heroku) or [AWS Lambda](/deployments/aws-lambda). +- Read on [app design](https://docs.slack.dev/surfaces/app-design) and compose fancy messages with blocks using [Block Kit Builder](https://app.slack.com/block-kit-builder) to prototype messages. diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 60f3eae81..0d80161e6 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -98,6 +98,7 @@ const config = { // switch to alucard when available in prism? theme: prismThemes.github, darkTheme: prismThemes.dracula, + additionalLanguages: ['bash'], }, codeblock: { showGithubLink: true, diff --git a/docs/sidebars.js b/docs/sidebars.js index 65c5e85f4..decb8cccb 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -7,13 +7,17 @@ const sidebars = { label: 'Bolt for Python', className: 'sidebar-title', }, + { + type: 'doc', + id: 'getting-started', + }, { type: 'html', value: '
' }, { type: 'category', label: 'Guides', collapsed: false, items: [ - "getting-started", + "building-an-app", { type: "category", label: "Slack API calls",