Slack次世代プラットフォームのアプリ開発でTrigger作成時に環境変数を利用する

tajima.ryo|2022年12月20日
アドベントカレンダー

この記事はLancers Advent Calendar 2022 19日目の記事です。

こんにちは、BPR推進部の田島(@eccyun)です。

Deno / TypeScriptでSlackアプリのコードを書きはじめたけど環境変数の使い方がいまいちしっくり来ていない人向けに、Triggerを作成する際に環境変数を利用するやり方をご紹介します。

よくあるTriggerの実装

早速ですが、以下のようなコードがあります。

triggers/hello.ts

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

const helloTrigger: Trigger<typeof HelloWorkFlow.definition> = {
    type: "event",
    name: "Hello.",
    workflow: "#/workflows/hello",
    event: {
        event_type: "slack#/events/message_posted",
        channel_ids: ["C1234567890"],
        filter: {
            version: 1,
            root: {
                statement: "{{data.text}} == Hello",
            },
        },
    },
    inputs: {
        interactivity: {
            value: "{{data.interactivity}}",
         },
         channel_id: {
             value: "{{data.channel_id}}",
         },
    },
};

export default helloTrigger;

上のコードは一般的なmessage_postedイベントを使ったTriggerの実装です。C1234567890のIDを持つチャンネルでHelloとポストするとそれをトリガーにWorkFlowが実行されるコードになっています。

対応するWorkFlowを実装しCLI上でslack trigger createするのがよくある流れですが、実運用するにあたりチャンネルIDがそのまま書かれているのがなんとなく気になってしまいます。

環境変数にチャンネルのIDを定義して、そちらを参照する形でやってみよう。というのが本記事の内容になります。

Triggerを作成する際に環境変数を利用する

定義した環境変数はFunctionの引数から取れるようになっています。

.env

CHANNEL_ID="C1234567890"

functions/hello.ts

import { DefineFunction, SlackFunction } from "deno-slack-sdk/mod.ts";
import { SlackAPI } from "deno-slack-api/mod.ts";
import HelloWorkFlow from "../workflows/hello.ts";

export const HelloDefinition = DefineFunction({
    callback_id: "hello",
    title: "Create Hello Trigger",
    description: "",
    source_file: "functions/hello.ts",
});

export default SlackFunction(HelloDefinition,({ token, env }) => {
    console.log(env["CHANNEL_ID"]); // CHANNEL_IDの値「1234567890」が出力される
    return {completed : true}
  },
);

TriggerはFunctionの処理内でも追加出来るようになっています。そのためFunction引数から環境変数を受け取りつつ処理内でTriggerを追加すると良さそうです。

実際に冒頭で紹介したmessage_postedイベントを使ったTriggerの追加をFunction内で行うようにしたコードが以下になります。

functions/hello.ts

import { DefineFunction, SlackFunction } from "deno-slack-sdk/mod.ts";
import { SlackAPI } from "deno-slack-api/mod.ts";
import HelloWorkFlow from "../workflows/hello.ts";

export const HelloDefinition = DefineFunction({
    callback_id: "hello",
    title: "Create Hello Trigger",
    description: "",
    source_file: "functions/hello.ts",
});


export default SlackFunction(HelloDefinition,({ token, env }) => {
    const client = SlackAPI(token, {});
    const newTrigger = client.workflows.triggers.create<typeof HelloWorkFlow.definition>({
        type : "event",
        name : "Hello.",
        workflow : "#/workflows/hello",
        event: {
            event_type: "slack#/events/message_posted",
            channel_ids: [env["CHANNEL_ID"]],
            filter: {
                version: 1,
                root: {
                    statement: "{{data.text}} == Hello",
                },
            },
        },
        inputs: {
            interactivity: {
                value: "{{data.interactivity}}",
            },
            channel_id: {
                value: "{{data.channel_id}}",
            },
        },
    });
    return { completed : true}
  },
);

環境変数を使ってTriggerを追加するためにこのFunctionを使ったWorkflowを作ってそれを実行するTriggerを作る必要があります。

Triggerを追加するWorkflowを動かすためのTriggerを作るようなイメージです、ちょっとややこしくなってきました。

いろいろなやり方があるかとは思うのですが、今回はシンプルにLink Triggerを使います。

triggers/add_hello_trigger.ts

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

const addHello: Trigger<typeof AddHelloTriggerWorkflow.definition> = {
    type: "shortcut",
    name: "add Hello Trigger",
    description: "",
    workflow: "#/workflows/add_hello_trigger_workflow",
    inputs: {
        interactivity: {
            value: "{{data.interactivity}}",
        },
        channel: {
            value: "{{data.channel_id}}",
        },
    },
};

export default addHello;

workflows/add_hello_trigger.ts

import { DefineWorkflow, Schema } from "deno-slack-sdk/mod.ts";
import { HelloDefinition } from "../functions/hello.ts";

const AddHelloTriggerWorkflow = DefineWorkflow({
    callback_id: "add_hello_trigger_workflow",
    title: "Add Hello Trigger",
    description: "",
    input_parameters: {
        properties: {
            interactivity: {
                type: Schema.slack.types.interactivity,
            },
            channel: {
                type: Schema.slack.types.channel_id,
            },
        },
        required: ["interactivity"],
    },
});

AddHelloTriggerWorkflow.addStep(HelloDefinition,{});

AddHelloTriggerWorkflow.addStep(Schema.slack.functions.SendMessage, {
    channel_id : AddHelloTriggerWorkflow.inputs.channel,
    message : "Triggerを追加しました.",
});

export default AddHelloTriggerWorkflow;

manifest.ts

import { Manifest } from "deno-slack-sdk/mod.ts";
import AddHelloTriggerWorkflow from "./workflows/add_hello_trigger.ts";

export default Manifest({
    name: "MySampleProject",
    description:"",
    icon: "assets/default_new_app_icon.png",
    workflows: [AddHelloTriggerWorkflow],
    outgoingDomains: [],
    // Function内でTriggerを作成するにあたり"triggers:write"を追加しておくこと
    botScopes: ["commands", "chat:write", "chat:write.public", "triggers:write", "channels:history", "groups:history", "im:read", "mpim:read"],
});

これは先に定義したfunction/hello.tsで定義しているFunctionを実行し、完了したらTriggerを追加しました.とBotがポストするWorkflowです。

Link Triggerを追加してWorkflowを実行するとこんな感じで結果が返ってくるようになります。

ここまでやると追加したTriggerに紐づくWorkflowが実行出来るようになります。(以下は一例です)

さいごに

今回紹介してなんとなく感じれたかなとは思うのですが、環境変数はちゃんと使おうとすると一手間かかってしまう印象です。

とは言え、プラットフォームが推奨するやり方に従ったほうが安全かと思うので、今後もしっかりとやっていきたいところです。

明日の記事は同じBPR推進部に所属している菱川さんです。お楽しみに〜。