自チーム向けにサーバーレスなSlackbot「おはクマbot」をCDKで構築してみた
こんにちは。AWS事業本部のKyoです。
前回同様、個人開発で社内向けのオレオレツールを作ったのでご紹介します。今回は自チーム向けの「おはクマbot」です。
前回?
おはクマbot概要
わたしの所属するヒグマチームでは「おはクマ」という朝の挨拶が定着しており、毎日以下のようなやりとりが行われています。
クマーのリアクションでコールアンドレスポンスされていますね。
今回開発したおはクマbotはその名の通り、「おはクマ」というSlackの発言に対して、データベースからランダムにクマ情報を返すSlackbotです。狙いは、ちょっとした賑やかしと雑談のタネにでもなったらいいなというところです。
アーキテクチャ
Slack社の提供するBoltというNode.jsのフレームワークを採用しています。それをAPI Gateway + Lambda + DynamoDBというサーバーレスな構成で動かしています。これらはCDKで一括管理されています。
以下のブログの内容にDynamoDB関連の処理を追加した形ですね。Slackアプリの作成やアーキテクチャについてはそちらをご参照ください。
ロジック
前述の通り、おはクマbotは「おはクマ」というワードに応答して、ランダムにクマ情報を返します(正規表現で多少の表記ゆれにも対応しています)。
ランダムにクマ情報を返すロジックはおみくじのようなもので、ポイントはDynamoDBのパーティションキーに連番のIDを採用していることです。
まず、DynamoDBをスキャンして、テーブルに含まれるアイテムの個数を取得します。これをもとに、最小値: 1、最大値: アイテムの個数、の範囲で乱数を生成します。得られた値をIDとして、テーブルから対応するアイテム、すなわちクマ情報を取得します。
実装としては以下のような形になります。
const getRandomItemInfo = async (): Promise<string> => { const getRandomItemId = async (): Promise<number> => { type Response = { Count: number; ScannedCount: number; }; const params = { TableName: tableName, Select: 'COUNT', }; const response: Response = await docClient.scan(params).promise(); const randomItemId: number = Math.floor(Math.random() * response.Count) + 1; return randomItemId; }; const getItemInfo = async (id: number): Promise<string> => { type Response = { Item: BearInfo; }; const params = { TableName: tableName, Key: { id: id, }, }; const response: Response = await docClient.get(params).promise(); const itemInfo: string = JSON.stringify(response.Item); return itemInfo; }; const itemId: number = await getRandomItemId(); const itemInfo: string = await getItemInfo(itemId); return itemInfo; };
セキュリティを意識するのであれば、連番のIDではなくUUIDを採用すべきところかもしれませんが、おはクマbotが扱うのは私が適当にまとめたクマ情報なので、今回はロジックの都合に合わせて連番のIDを採用しました。
加えて、なるべく管理コストを下げるために自前で画像データはもっていません。以下の通り、イメージの情報はURLだけで、展開はSlackに任せています。
おわりに
今回はSlackのチームチャンネルをちょっと賑やかすサーバーレスBotを作ってみました。
事前準備として、CDKのワークショップをやってみたり、AWS SDK for JavaScriptからDynamoDBを触ってみたりと実装に含まれていない部分でも得られたものは多かったと思います。
ちなみにクマ情報は私がマネジメントコンソールを経由でDynamoDBに直接入力しています。クマ情報を集めたりまとめたりする事自体はそこまで苦でないのですが、このあたたかみのある入力作業はもう少しスマートに行いたいところです。