-
Notifications
You must be signed in to change notification settings - Fork 255
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Japanese translation of Advanced concepts pages (#354)
- Loading branch information
Showing
13 changed files
with
561 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
--- | ||
title: アダプター | ||
lang: ja-jp | ||
slug: adapters | ||
order: 0 | ||
--- | ||
|
||
<div class="section-content"> | ||
アダプターは Slack から届く受信イベントの受付とパーズを担当し、それらのイベントを <a href="https://github.com/slackapi/bolt-python/blob/main/slack_bolt/request/request.py">`BoltRequest`</a> の形式に変換して Bolt アプリに引き渡します。 | ||
|
||
デフォルトでは、Bolt の組み込みの <a href="https://docs.python.org/3/library/http.server.html">`HTTPServer`</a> アダプターが使われます。このアダプターは、ローカルで開発するのには問題がありませんが、<b>本番環境での利用は推奨されていません</b>。Bolt for Python には複数の組み込みのアダプターが用意されており、必要に応じてインポートしてアプリで使用することができます。組み込みのアダプターは Flask、Django、Starlette をはじめとする様々な人気の Python フレームワークをサポートしています。これらのアダプターは、あなたが選択した本番環境で利用可能な Webサーバーとともに利用することができます。 | ||
|
||
アダプターを使用するには、任意のフレームワークを使ってアプリを開発し、そのコードに対応するアダプターをインポートします。その後、アダプターのインスタンスを初期化して、受信イベントの受付とパーズを行う関数を呼び出します。 | ||
|
||
すべてのアダプターの一覧と、設定や使い方のサンプルは、リポジトリの <a href="https://github.com/slackapi/bolt-python/tree/main/examples">`examples` フォルダ</a>をご覧ください。 | ||
</div> | ||
|
||
```python | ||
from slack_bolt import App | ||
app = App( | ||
signing_secret=os.environ.get("SIGNING_SECRET"), | ||
token=os.environ.get("SLACK_BOT_TOKEN") | ||
) | ||
|
||
# ここには Flask 固有の記述はありません | ||
# App はフレームワークやランタイムに一切依存しません | ||
@app.command("/hello-bolt") | ||
def hello(body, ack): | ||
ack(f"Hi <@{body['user_id']}>!") | ||
|
||
# Flask アプリを初期化します | ||
from flask import Flask, request | ||
flask_app = Flask(__name__) | ||
|
||
# SlackRequestHandler は WSGI のリクエストを Bolt のインターフェイスに合った形に変換します | ||
# Bolt レスポンスからの WSGI レスポンスの作成も行います | ||
from slack_bolt.adapter.flask import SlackRequestHandler | ||
handler = SlackRequestHandler(app) | ||
|
||
# Flask アプリへのルートを登録します | ||
@flask_app.route("/slack/events", methods=["POST"]) | ||
def slack_events(): | ||
# handler はアプリのディスパッチメソッドを実行します | ||
return handler.handle(request) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
--- | ||
title: Async(asyncio)の使用 | ||
lang: ja-jp | ||
slug: async | ||
order: 2 | ||
--- | ||
|
||
<div class="section-content"> | ||
非同期バージョンの Bolt を使用する場合は、`App` の代わりに `AsyncApp` インスタンスをインポートして初期化します。`AsyncApp` では <a href="https://docs.aiohttp.org/">AIOHTTP</a> を使って API リクエストを行うため、`aiohttp` をインストールする必要があります(`requirements.txt` に追記するか、`pip install aiohttp` を実行します)。 | ||
|
||
非同期バージョンのプロジェクトのサンプルは、リポジトリの <a href="https://github.com/slackapi/bolt-python/tree/main/examples">`examples` フォルダ</a>にあります。 | ||
</div> | ||
|
||
```python | ||
# aiohttp のインストールが必要です | ||
from slack_bolt.async_app import AsyncApp | ||
app = AsyncApp() | ||
|
||
@app.event("app_mention") | ||
async def handle_mentions(event, client, say): # 非同期関数 | ||
api_response = await client.reactions_add( | ||
channel=event["channel"], | ||
timestamp=event["ts"], | ||
name="eyes", | ||
) | ||
await say("What's up?") | ||
|
||
if __name__ == "__main__": | ||
app.start(3000) | ||
``` | ||
|
||
<details class="secondary-wrapper"> | ||
<summary class="section-head" markdown="0"> | ||
<h4 class="section-head">他のフレームワークを使用する</h4> | ||
</summary> | ||
|
||
<div class="secondary-content" markdown="0"> | ||
|
||
`AsyncApp#start()` では内部的に [`AIOHTTP`](https://docs.aiohttp.org/) のWebサーバーが実装されています。必要に応じて、受信リクエストの処理に `AIOHTTP` 以外のフレームワークを使用することができます。 | ||
|
||
この例では [Sanic](https://sanicframework.org/) を使用しています。すべてのアダプターのリストについては、[`adapter` フォルダ](https://github.com/slackapi/bolt-python/tree/main/slack_bolt/adapter) を参照してください。 | ||
|
||
以下のコマンドを実行すると、必要なパッケージをインストールして、Sanic サーバーをポート 3000 で起動します。 | ||
|
||
```bash | ||
# 必要なパッケージをインストールします | ||
pip install slack_bolt sanic uvicorn | ||
# ソースファイルを async_app.py として保存します | ||
uvicorn async_app:api --reload --port 3000 --log-level debug | ||
``` | ||
</div> | ||
|
||
```python | ||
from slack_bolt.async_app import AsyncApp | ||
app = AsyncApp() | ||
|
||
# ここには Sanic に固有の記述はありません | ||
# AsyncApp はフレームワークやランタイムに依存しません | ||
@app.event("app_mention") | ||
async def handle_app_mentions(say): | ||
await say("What's up?") | ||
|
||
import os | ||
from sanic import Sanic | ||
from sanic.request import Request | ||
from slack_bolt.adapter.sanic import AsyncSlackRequestHandler | ||
|
||
# App のインスタンスから Sanic 用のアダプターを作成します | ||
app_handler = AsyncSlackRequestHandler(app) | ||
# Sanic アプリを作成します | ||
api = Sanic(name="awesome-slack-app") | ||
|
||
@api.post("/slack/events") | ||
async def endpoint(req: Request): | ||
# app_handler では内部的にアプリのディスパッチメソッドが実行されます | ||
return await app_handler.handle(req) | ||
|
||
if __name__ == "__main__": | ||
api.run(host="0.0.0.0", port=int(os.environ.get("PORT", 3000))) | ||
``` | ||
</details> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
--- | ||
title: 認可(Authorization) | ||
lang: ja-jp | ||
slug: authorization | ||
order: 5 | ||
--- | ||
|
||
<div class="section-content"> | ||
認可(Authorization)は、Slack からの受信イベントを処理するにあたって、どのようなSlack | ||
クレデンシャル (ボットトークンなど) を使用可能にするかを決定するプロセスです。 | ||
|
||
単一のワークスペースにインストールされるアプリでは、`token` パラメーターを使って `App` のコンストラクターにボットトークンを渡すという、シンプルな方法が使えます。それに対して、複数のワークスペースにインストールされるアプリでは、次の 2 つの方法のいずれかを使用する必要があります。簡単なのは、組み込みの OAuth サポートを使用する方法です。OAuth サポートは、OAuth フロー用のURLのセットアップとstateの検証を行います。詳細は「[OAuth を使った認証](#authenticating-oauth)」セクションを参照してください。 | ||
|
||
よりカスタマイズできる方法として、`App` をインスタンス化する関数に`authorize` パラメーターを指定する方法があります。`authorize` 関数から返される [`AuthorizeResult` のインスタンス](https://github.com/slackapi/bolt-python/blob/main/slack_bolt/authorization/authorize_result.py)には、どのユーザーがどこで発生させたイベントかを示す情報が含まれます。 | ||
|
||
`AuthorizeResult` には、いくつか特定のプロパティを指定する必要があり、いずれも `str` 型です。 | ||
|
||
|
||
- **`bot_token`**(xoxb)*または* **`user_token`**(xoxp): どちらか一方が**必須**です。ほとんどのアプリでは、デフォルトの `bot_token` を使用すればよいでしょう。トークンを渡すことで、`say()` などの組み込みの関数を機能させることができます。 | ||
- **`bot_user_id`** および **`bot_id`** : `bot_token` を使用する場合に指定します。 | ||
- **`enterprise_id`** および **`team_id`** : アプリに届いたイベントから見つけることができます。 | ||
- **`user_id`** : `user_token` を使用する場合に必須です。 | ||
</div> | ||
|
||
```python | ||
import os | ||
from slack_bolt import App | ||
# AuthorizeResult クラスをインポートします | ||
from slack_bolt.authorization import AuthorizeResult | ||
|
||
# これはあくまでサンプル例です(ユーザートークンがないことを想定しています) | ||
# 実際にはセキュアな DB に認可情報を保存してください | ||
installations = [ | ||
{ | ||
"enterprise_id":"E1234A12AB", | ||
"team_id":"T12345", | ||
"bot_token": "xoxb-123abc", | ||
"bot_id":"B1251", | ||
"bot_user_id":"U12385" | ||
}, | ||
{ | ||
"team_id":"T77712", | ||
"bot_token": "xoxb-102anc", | ||
"bot_id":"B5910", | ||
"bot_user_id":"U1239", | ||
"enterprise_id":"E1234A12AB" | ||
} | ||
] | ||
|
||
def authorize(enterprise_id, team_id, logger): | ||
# トークンを取得するためのあなたのロジックをここに記述します | ||
for team in installations: | ||
# 一部のチームは enterprise_id を持たない場合があります | ||
is_valid_enterprise = True if (("enterprise_id" not in team) or (enterprise_id == team["enterprise_id"])) else False | ||
if ((is_valid_enterprise == True) and (team["team_id"] == team_id)): | ||
# AuthorizeResult のインスタンスを返します | ||
# bot_id と bot_user_id を保存していない場合、bot_token を使って `from_auth_test_response` を呼び出すと、自動的に取得できます | ||
return AuthorizeResult( | ||
enterprise_id=enterprise_id, | ||
team_id=team_id, | ||
bot_token=team["bot_token"], | ||
bot_id=team["bot_id"], | ||
bot_user_id=team["bot_user_id"] | ||
) | ||
|
||
logger.error("No authorization information was found") | ||
|
||
app = App( | ||
signing_secret=os.environ["SLACK_SIGNING_SECRET"], | ||
authorize=authorize | ||
) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
--- | ||
title: コンテキストの追加 | ||
lang: ja-jp | ||
slug: context | ||
order: 7 | ||
--- | ||
|
||
<div class="section-content"> | ||
すべてのリスナーは `context` ディクショナリにアクセスできます。リスナーはこれを使ってイベントの付加情報を得ることができます。受信イベントに含まれる `user_id`、`team_id`、`channel_id`、`enterprise_id` などの情報は、Bolt によって自動的に設定されます。 | ||
|
||
`context` は単純なディクショナリで、変更を直接加えることもできます。 | ||
</div> | ||
|
||
```python | ||
# ユーザーID を使って外部のシステムからタスクを取得するリスナーミドルウェア | ||
def fetch_tasks(context, event, next): | ||
user = event["user"] | ||
try: | ||
# get_tasks は、ユーザー ID に対応するタスクのリストを DB から取得します | ||
user_tasks = db.get_tasks(user) | ||
tasks = user_tasks | ||
except Exception: | ||
# タスクが見つからなかった場合 get_tasks() は例外を投げます | ||
tasks = [] | ||
finally: | ||
# ユーザーのタスクを context に設定します | ||
context["tasks"] = tasks | ||
next() | ||
|
||
# section のブロックのリストを作成するリスナーミドルウェア | ||
def create_sections(context, next): | ||
task_blocks = [] | ||
# 先ほどのミドルウェアを使って context に追加した各タスクについて、処理を繰り返します | ||
for task in context["tasks"]: | ||
task_blocks.append( | ||
{ | ||
"type": "section", | ||
"text": { | ||
"type": "mrkdwn", | ||
"text": f"*{task['title']}* | ||
{task['body']}" | ||
}, | ||
"accessory": { | ||
"type": "button", | ||
"text": { | ||
"type": "plain_text", | ||
"text":"See task" | ||
}, | ||
"url": task["url"], | ||
} | ||
} | ||
) | ||
# ブロックのリストを context に設定します | ||
context["blocks"] = task_blocks | ||
next() | ||
|
||
# ユーザーがアプリのホームを開くのをリッスンします | ||
# fetch_tasks ミドルウェアを含めます | ||
@app.event( | ||
event = "app_home_opened", | ||
middleware = [fetch_tasks, create_sections] | ||
) | ||
def show_tasks(event, client, context): | ||
# ユーザーのホームタブにビューを表示します | ||
client.views_publish( | ||
user_id=event["user"], | ||
view={ | ||
"type": "home", | ||
"blocks": context["blocks"] | ||
} | ||
) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
--- | ||
title: カスタムのアダプター | ||
lang: ja-jp | ||
slug: custom-adapters | ||
order: 1 | ||
--- | ||
|
||
<div class="section-content"> | ||
[アダプター](#adapters)はフレキシブルで、あなたが使用したいフレームワークに合わせた調整も可能です。アダプターでは、次の 2 つの要素が必須となっています。 | ||
|
||
- `__init__(app:App)` : コンストラクター。Bolt の `App` のインスタンスを受け取り、保持します。 | ||
- `handle(req:Request)` : Slack からの受信リクエストを受け取り、解析を行う関数。通常は `handle()` という名前です。リクエストを [`BoltRequest`](https://github.com/slackapi/bolt-python/blob/main/slack_bolt/request/request.py) のインスタンスに合った形にして、保持している Bolt アプリに引き渡します。 | ||
|
||
`BoltRequest` のインスタンスの作成では、以下の 4 種類のパラメーターを指定できます。 | ||
|
||
| パラメーター | 説明 | 必須 | | ||
|-----------|-------------|-----------| | ||
| `body: str` | そのままのリクエストボディ | **Yes** | | ||
| `query: any` | クエリストリング | No | | ||
| `headers:Dict[str, Union[str, List[str]]]` | リクエストヘッダー | No | | ||
| `context:BoltContext` | リクエストのコンテキスト情報 | No | | ||
|
||
アダプターは、Bolt アプリからの [`BoltResponse` のインスタンス](https://github.com/slackapi/bolt-python/blob/main/slack_bolt/response/response.py)を返します。 | ||
|
||
カスタムのアダプターに関連した詳しいサンプルについては、[組み込みのアダプター](https://github.com/slackapi/bolt-python/tree/main/slack_bolt/adapter)の実装を参考にしてください。 | ||
</div> | ||
|
||
```python | ||
# Flask で必要なパッケージをインポートします | ||
from flask import Request, Response, make_response | ||
|
||
from slack_bolt.app import App | ||
from slack_bolt.request import BoltRequest | ||
from slack_bolt.response import BoltResponse | ||
|
||
# この例は Flask アダプターを簡略化したものです | ||
# もう少し詳しい完全版のサンプルは、adapter フォルダをご覧ください | ||
# github.com/slackapi/bolt-python/blob/main/slack_bolt/adapter/flask/handler.py | ||
|
||
# HTTP リクエストを取り込み、標準の BoltRequest に変換します | ||
def to_bolt_request(req:Request) -> BoltRequest: | ||
return BoltRequest( | ||
body=req.get_data(as_text=True), | ||
query=req.query_string.decode("utf-8"), | ||
headers=req.headers, | ||
) | ||
|
||
# BoltResponse を取り込み、標準の Flask レスポンスに変換します | ||
def to_flask_response(bolt_resp:BoltResponse) -> Response: | ||
resp:Response = make_response(bolt_resp.body, bolt_resp.status) | ||
for k, values in bolt_resp.headers.items(): | ||
for v in values: | ||
resp.headers.add_header(k, v) | ||
return resp | ||
|
||
# アプリからインスタンス化します | ||
# Flask アプリを受け取ります | ||
class SlackRequestHandler: | ||
def __init__(self, app:App): | ||
self.app = app | ||
|
||
# Slack からリクエストが届いたときに | ||
# Flask アプリの handle() を呼び出します | ||
def handle(self, req:Request) -> Response: | ||
# この例では OAuth に関する部分は扱いません | ||
if req.method == "POST": | ||
# Bolt へのリクエストをディスパッチし、処理とルーティングを行います | ||
bolt_resp:BoltResponse = self.app.dispatch(to_bolt_request(req)) | ||
return to_flask_response(bolt_resp) | ||
|
||
return make_response("Not Found", 404) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
--- | ||
title: エラーの処理 | ||
lang: ja-jp | ||
slug: errors | ||
order: 3 | ||
--- | ||
|
||
<div class="section-content"> | ||
リスナー内でエラーが発生した場合に try/except ブロックを使用して直接エラーを処理することができます。アプリに関連するエラーは、`BoltError` 型です。Slack API の呼び出しに関連するエラーは、`SlackApiError` 型となります。 | ||
|
||
デフォルトでは、すべての処理されなかった例外のログはグローバルのエラーハンドラーによってコンソールに出力されます。グローバルのエラーを開発者自身で処理するには、`app.error(fn)` 関数を使ってグローバルのエラーハンドラーをアプリに設定します。 | ||
</div> | ||
|
||
```python | ||
@app.error | ||
def custom_error_handler(error, body, logger): | ||
logger.exception(f"Error: {error}") | ||
logger.info(f"Request body: {body}") | ||
``` |
Oops, something went wrong.