Slack オートメーション: イベントトリガーの channel_ids ハードコーディングが不要に！

こんにちは、Slack の[公式 SDK 開発](https://github.com/slackapi)と日本の Developer Relations を担当している瀬良 (@seratch) と申します 👋

Slack のオートメーションプラットフォームのイベントトリガーに、この記事のタイトル通り、使い勝手を大幅に改善する機能追加がありましたので、日本語でもご紹介します。

## Slack オートメーションプラットフォームとは？

「Slack オートメーションプラットフォームって何？」という方は、少し長めの記事ですが、まずはこちらの記事をご覧ください。

https://qiita.com/seratch/items/ecc16b845483c9d6f9e1

英語のドキュメントはこちらです：

https://api.slack.com/automation

このプラットフォームでワークフローを開始する手段である「トリガー」の中で「[イベントトリガー](https://api.slack.com/automation/triggers/event)」というものがあるのですが、今回の記事はこのトリガーのアップデートに関する解説です。

## イベントトリガーの種類

イベントトリガーには、以下の二種類があります：

- **(A)** すでにチャンネルが存在していて、その中で起きたイベント
- **(B)** 既存の特定のチャンネルに紐づくわけではないイベント

**(A)** は新しいメッセージの投稿である message_posted やメッセージにリアクションがついたときのイベントである reaction_added などがあります。

**(B)** の例としてはワークスペースに新しいメンバーが参加したときの user_joined_team であったり、新しいチャンネルが作成されたときの channel_created などがあります。

最もシンプルなイベントトリガーの設定方法については、以下の記事で日本語解説していますので、初めての方はこちらもぜひ読んでみてください。

https://qiita.com/seratch/items/a4770243f3799b553e9c


## 何が変わったのか？

**(A)** では、これまで以下のように `event.channel_ids` として、ワークフローを利用したいチャンネルの ID の配列を**トリガーの定義内にハードコーディング**する必要がありました。

```typescript
import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";
export const workflow = DefineWorkflow({
  callback_id: "example-workflow",
  ...
});

import { Trigger } from "deno-slack-api/types.ts";

const trigger: Trigger<typeof workflow.definition> = {
  type: "event",
  name: "A sample trigger",
  workflow: `#/workflows/${workflow.definition.callback_id}`,
  event: {
    event_type: "slack#/events/reaction_added",
    channel_ids: ["C12345", "C23456"], // これが必須！
    filter: { version: 1, root: { statement: "{{data.reaction}} == eyes" } },
  },
  inputs: {
    channel_id: { value: "{{data.channel_id}}" },
    user_id: { value: "{{data.user_id}}" },
    message_ts: { value: "{{data.message_ts}}" },
  },
};
export default trigger;
```

ピンポイントで抜粋すると、この部分です：

```typescript
    channel_ids: ["C12345", "C23456"], // これが必須！
```


**この仕様は別のチャンネルでもワークフローを有効にしたいという場合に不便でした。** そのような場合には、既存のトリガーを一旦削除（`slack trigger delete`）して、コード内の `event.channel_ids` にアイテムを追加して再作成（`slack trigger create`）するか、新しいトリガーの定義を増やして新規で追加（`slack triggger create`）しなければならかったからです。

この問題に対するワークアラウンドとして私が編み出したのが「**イベントトリガーの設定用の別のワークフローを同じアプリの中に持つ**」という手法です。これはイベントトリガーを必要とするメインのワークフローに加えて、サブのワークフローを持ち、そのサブのワークフローのモーダルダイアログ経由で channel_ids を書き換えて再作成、ボットユーザーもそこに招待するという処理の流れです。

実装例の例をリンクしておきます。

* [設定用ワークフローを起動するリンクトリガー](https://github.com/slack-samples/deno-message-translator/blob/main/triggers/configurator.ts)
* [設定用ワークフローの定義](https://github.com/slack-samples/deno-message-translator/blob/main/workflows/configurator.ts)
* [設定用モーダルダイアログを提供するカスタムファンクション](https://github.com/slack-samples/deno-message-translator/blob/main/functions/configure.ts)
* [workflows.triggers.create|update API でトリガーを設定する処理](https://github.com/slack-samples/deno-message-translator/blob/main/functions/internals/trigger_operations.ts)

これは、上記の deno-message-translator だけでなく、https://github.com/slack-samples のさまざまなサンプルアプリやお客様が開発されているカスタムのアプリコードでも広く使われています。

ただ、こんなコードを書かずに済むならその方がよいわけですね・・・

## all_resources: true で channel_ids が不要に！

deno-slack-sdk 2.10.0 / deno-slack-api v2.4.0 から、それがついに channel_ids の指定が不要となりました。`import_map.json` が以下のバージョンかそれよりも新しいものにしてください。

```json
{
  "imports": {
    "deno-slack-sdk/": "https://deno.land/x/deno_slack_sdk@2.10.0/",
    "deno-slack-api/": "https://deno.land/x/deno_slack_api@2.4.0/"
  }
}
```


新しく追加されたオプションは `all_resources: boolean` というフラグで、これを true にすると `channel_ids` はもはや不要です。

```typescript
const trigger: Trigger<typeof workflow.definition> = {
  type: "event",
  name: "A sample trigger",
  workflow: `#/workflows/${workflow.definition.callback_id}`,
  event: {
    event_type: "slack#/events/reaction_added",
    all_resources: true, // これだけ！
    filter: { version: 1, root: { statement: "{{data.reaction}} == eyes" } },
  },
  inputs: {
    channel_id: { value: "{{data.channel_id}}" },
    user_id: { value: "{{data.user_id}}" },
    message_ts: { value: "{{data.message_ts}}" },
  },
};
export default trigger;
```

このオプションを指定してイベントトリガーを作成した場合、以降はトリガーをいじる必要ありません。次にやることは**このワークフローを起動したいチャンネルにボットユーザーを招待するだけ**です。

上の例であれば、ボットユーザーを招待した後にそのチャンネルでメッセージに `:eyes"` リアクションがつくとワークフローが起動されることになります。

## 既存のワークフローを移行したい場合

既存のトリガーは、以下の手順で削除できます：

- `slack trigger list` 対象のアプリを指定して、設定されているトリガーの一覧を表示
- 不要なトリガーを `slack trigger delete --trigger-id (Ft から始まる ID)` を実行してを削除

次に `all_resources: true` を設定した新しいトリガー定義を `slack trigger create --trigger-def (ソースファイルのパス)` で反映すれば完了です。

通常、ボットユーザーは対象のチャンネルに招待済のはずですが、何らかの理由でそうなっていない場合は手動でボットを招待してみてください。それ以降はイベントにトリガーが反応するようになるはずです。

## 再掲：`import_map.json` の設定に注意！

繰り返しとなりますが、`import_map.json` で指定されている deno-slack-sdk / deno-slack-api のバージョンが以下のものかそれより新しいものでなければ、`all_resources` オプションは使えないので、必ず最新のバージョンにしてください。 `slack upgrade` コマンドでも更新が可能です。

```json
{
  "imports": {
    "deno-slack-sdk/": "https://deno.land/x/deno_slack_sdk@2.10.0/",
    "deno-slack-api/": "https://deno.land/x/deno_slack_api@2.4.0/"
  }
}
```


## 終わりに

ようやく簡単かつ直感的な設定方法になりました！（これまでがやりづらかっただけとも言えますが・・ 🙇）

前に試してみて「使いづらいな・・」と感じた方もぜひもう一度試してみてください！