「Python で Slack API や Webhook を扱うなら公式 SDK(slack-sdk/slack-bolt)を使おう」シリーズの記事です。公式 SDK についての概要、他にも記事がリンクされていますので、こちらのエントリーページにもアクセスしてみてください。
Slack 公式 SDK の asyncio サポート
このページに辿り着いたということは asyncio を活用してアプリケーション開発をされていますか?
Slack 公式 SDK である slack-sdk は AIOHTTP を HTTP クライアントとして利用する形で asyncio をサポートしています。
この記事ではそのモジュールの使用方法をコード例とともに紹介していきます。
なお、こちらの記事は「Slack Python SDK でチャンネルにメッセージを投稿しよう」という記事をベースにしています。もし asyncio ではない一般的な Python コードの例を探している場合は、そちらの記事を参考にしてください。
AIOHTTP を使ってチャンネルにメッセージを投稿する
この記事では slack-sdk
PyPI パッケージを使って Slack のチャンネル、DM にメッセージを投稿するコーディングについて解説します。以下の内容を説明していきます。
-
chat.postMessage
API でメッセージを投稿 - Incoming Webhooks でメッセージを投稿
- メッセージを更新・削除
- エフェメラルメッセージを投稿
- ユーザーインタラクションに対して返信
盛りだくさんになっていますが、いきなりすべてを理解する必要はありませんので、必要になったときにこの記事を読み返してみてください。
chat.postMessage
API でメッセージを投稿
それでは早速 chat.postMessage
API の使い方から始めていきましょう。まずこの API を使うためには chat:write
という OAuth スコープが必要となります。この権限を持つアプリの設定は以下のようになります。早速、こちらのリンクから作成してみてください。
_metadata:
major_version: 1
minor_version: 1
display_information:
name: chat.postMessage App
features:
app_home:
messages_tab_enabled: true
messages_tab_read_only_enabled: false
bot_user:
display_name: chat.postMessage Bot
oauth_config:
scopes:
bot:
- chat:write
# この記事では詳細を解説しませんが、この権限があれば bot user は public チャンネルに限り、チャンネルに参加せずにメッセージを投稿できるようになります
- chat:write.public
# この記事では詳細を解説しませんが、アプリからの投稿ではありますが username / icon_emoji / icon_url を変更して見た目を変えることができるようになります
- chat:write.customize
作成できたら「Install to Workspace」ボタンから Slack ワークスペースにインストールすると Settings > Install App のページ内の「Bot User OAuth Token」という名前で xoxb-
で始まるトークンが発行されているかと思います。これを SLACK_BOT_TOKEN
という名前で環境変数に設定しておいてください。
export SLACK_BOT_TOKEN=xoxb-111-222-xxxx
以上で、この記事のサンプルを動かすための Slack アプリの設定は完了です。Python プロジェクトを設定してコードを実行していきましょう。
この記事のコードは全て Python 3.6 以上で動作します。python3 --version
でバージョンを確認してください。この記事では Poetry を使って説明していきます。インストールしていない人はこちらを参考にしてください。
それではプロジェクトを作っていきましょう。
# 新しいプロジェクトを作成
poetry new chat_postMessage_app
cd chat_postMessage_app/
# 必要に応じて poetry env use 3.9 など
# virtualenv を有効化
poetry shell
# slack-sdk と aiohttp を追加
poetry add slack-sdk aiohttp
requirements.txt であれば
slack-sdk>=3.13,<4
aiohttp>=3.7.3,<4
のようにしてください(バージョンは使用したいものに合わせてください)。
asyncio は Python の標準モジュールですが、slack-sdk が利用する aiohttp はあくまで広く利用されている 3rd party ライブラリです。slack-sdk をインストールするだけでは aiohttp は追加されませんので、必ず明にインストールするようにしてください。これでひとまず完了です。
とりあえず投稿してみる
まずはボットユーザーとしてメッセージを投稿してみましょう。以下のソースコードを bot.py
として保存してください。
import asyncio, logging, os
# デバッグレベルのログを出力します
logging.basicConfig(level=logging.DEBUG)
from slack_sdk.web.async_client import AsyncWebClient
from slack_sdk.errors import SlackApiError
# Web API クライアントを初期化します
client = AsyncWebClient(os.environ["SLACK_BOT_TOKEN"])
async def main():
try:
# chat.postMessage API を呼び出します
# メソッド呼び出しに await キーワードをつけるのを忘れずに!
response = await client.chat_postMessage(
channel="#random",
text=":wave: こんにちは!",
)
print(response)
except SlackApiError as e:
assert e.response["ok"] is False
assert e.response["error"] # str like 'invalid_auth', 'channel_not_found'
print(f"Got an error: {e.response['error']}")
# asyncio.run は簡単に async 関数を実行するためのユーティリティです
asyncio.run(main())
実行が成功すると以下のような出力になるはずです。
(.venv) bash-3.2$ export SLACK_BOT_TOKEN=xoxb-111-222-xxx
(.venv) bash-3.2$ python bot.py
DEBUG:slack_sdk.web.base_client:Sending a request - url: https://www.slack.com/api/chat.postMessage, query_params: {}, body_params: {}, files: {}, json_body: {'text': ':wave: こんにちは!', 'channel': '#random'}, headers: {'Content-Type': 'application/json;charset=utf-8', 'Authorization': '(redacted)', 'User-Agent': 'Python/3.9.1 slackclient/3.5.1 Darwin/20.4.0'}
DEBUG:slack_sdk.web.slack_response:Received the following response - status: 200, headers: { ... }, body: {'ok': True, 'channel': 'C111', 'ts': '1622017093.007700', 'message': {'bot_id': 'B111', 'type': 'message', 'text': ':wave: こんにちは!', 'user': 'U111', 'ts': '1622017093.007700', 'team': 'T111', 'bot_profile': {'id': 'B111', 'deleted': False, 'name': 'chat.postMessage App', 'updated': 1622016343, 'app_id': 'A111', 'icons': {'image_36': 'https://a.slack-edge.com/111/img/plugins/app/bot_36.png', 'image_48': 'https://a.slack-edge.com/111/img/plugins/app/bot_48.png', 'image_72': 'https://a.slack-edge.com/111/img/plugins/app/service_72.png'}, 'team_id': 'T111'}}}
そして Slack ワークスペースの #random
チャンネルに以下のようなメッセージが投稿されているはずです!
うまくいきましたか?おめでとうございます
ユーザーに成り代わっての投稿や blocks
、attachments
の利用方法など、WebClient
と何ら関わるところはありません。それらについてはこちらの記事を参考にしてください。
Incoming Webhooks でメッセージを投稿
基本的にはこちらの記事と同様なのですが、コード例が異なりますので、最初のコード例のみこちらに載せておきます。そこからのカスタマイズは特に変わるところはありません。
import asyncio, logging, os
# デバッグレベルのログを出力します
logging.basicConfig(level=logging.DEBUG)
# Web API クライアントを初期化します
from slack_sdk.webhook.async_client import AsyncWebhookClient
client = AsyncWebhookClient(os.environ["SLACK_WEBHOOK_URL"])
async def main():
# メッセージを送信します
# メソッド呼び出しに await キーワードをつけるのを忘れずに!
response = await client.send(text=":wave: こんにちは!")
print(f"status: {response.status_code} body: {response.body}")
# asyncio.run は簡単に async 関数を実行するためのユーティリティです
asyncio.run(main())
メッセージを更新・削除
それでは API を使ってメッセージの更新・削除もやってみましょう。
import asyncio, logging, os
# デバッグレベルのログを出力します
logging.basicConfig(level=logging.DEBUG)
# Web API クライアントを初期化します
from slack_sdk.web.async_client import AsyncWebClient
client = AsyncWebClient(os.environ["SLACK_BOT_TOKEN"])
async def main():
# 新しいメッセージを投稿 (await を忘れずに!)
new_message = await client.chat_postMessage(
channel="#random",
text=":wave: こんにちは!",
)
# わかりやすくするために sleep
await asyncio.sleep(2)
# 自分が投稿したメッセージを更新
await client.chat_update(
channel=new_message["channel"],
ts=new_message["ts"],
text=":wave: こんばんは!",
)
# わかりやすくするために sleep
await asyncio.sleep(2)
# 自分が投稿したメッセージを削除
await client.chat_delete(
channel=new_message["channel"],
ts=new_message["ts"],
)
# asyncio.run は簡単に async 関数を実行するためのユーティリティです
asyncio.run(main())
Slack チャンネル内での動作は以下のようになります。
エフェメラルメッセージを投稿
「エフェメラルメッセージ」とは、チャンネル内に投稿されていても特定のユーザーにだけ見えているメッセージです。Slack の画面上で「あなただけに表示されています(英語だと Only visible to you)」と表示されているメッセージを見たことがあるかもしれません。このメッセージは例えばスラッシュコマンドを実行したユーザーだけに「受け付けました!」のようなメッセージを表示したいときなどに便利です。では、このメッセージを API を使って送信してみましょう。
import asyncio, logging, os
# デバッグレベルのログを出力します
logging.basicConfig(level=logging.DEBUG)
# Web API クライアントを初期化します
from slack_sdk.web.async_client import AsyncWebClient
client = AsyncWebClient(os.environ["SLACK_BOT_TOKEN"])
async def main():
# TODO: 実際のユーザー ID に変更してください
user_id = "U03E94MK0"
# 場所として channel を指定、誰に対して表示するかで user を指定します
response = await client.chat_postEphemeral(
channel="#random",
user=user_id,
text=":wave: あなただけにお知らせです!",
)
# asyncio.run は簡単に async 関数を実行するためのユーティリティです
asyncio.run(main())
以下のようなメッセージが表示されたでしょうか?
割愛しますが、もちろん blocks
も問題なく使えます。
ユーザーインタラクションに対して返信
スラッシュコマンド、ショートカットなどへの応答でメッセージを返信したいという方は、ぜひこちらの response_url
に関する詳細な記事を参考にしてみてください。response_url
への HTTP リクエストには AsyncWebhookClient
を使うことができます。
まとめ
この記事では Slack API を使ってチャットにメッセージを投稿する方法について公式 Python SDK の asyncio 互換のコード例とともに網羅的に紹介しました。
繰り返しとなりますが、こちらの記事は「Slack Python SDK でチャンネルにメッセージを投稿しよう」という記事をベースにしています。もし asyncio ではない一般的な Python コードの例を探している場合は、そちらの記事を参考にしてください。
それでは