Skip to content

Commit

Permalink
Add Japanese translation of Advanced concepts pages (#354)
Browse files Browse the repository at this point in the history
  • Loading branch information
seratch authored May 28, 2021
1 parent f84bc94 commit 24e64c9
Show file tree
Hide file tree
Showing 13 changed files with 561 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/_advanced/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ order: 3
---

<div class="section-content">
If an error occurs in a listener, you can handle it directly using a `try`/`except` block. Errors associated with your app will be of type `BoltError`. Errors associated with calling Slack APIs will be of type `SlackApiError`.
If an error occurs in a listener, you can handle it directly using a try/except block. Errors associated with your app will be of type `BoltError`. Errors associated with calling Slack APIs will be of type `SlackApiError`.

By default, the global error handler will log all non-handled exceptions to the console. To handle global errors yourself, you can attach a global error handler to your app using the `app.error(fn)` function.
</div>
Expand Down
45 changes: 45 additions & 0 deletions docs/_advanced/ja_adapters.md
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)
```
81 changes: 81 additions & 0 deletions docs/_advanced/ja_async.md
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>
72 changes: 72 additions & 0 deletions docs/_advanced/ja_authorization.md
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
)
```
72 changes: 72 additions & 0 deletions docs/_advanced/ja_context.md
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"]
}
)
```
72 changes: 72 additions & 0 deletions docs/_advanced/ja_custom_adapters.md
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)
```
19 changes: 19 additions & 0 deletions docs/_advanced/ja_errors.md
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}")
```
Loading

0 comments on commit 24e64c9

Please sign in to comment.