APIの学習がきっかけではあったのだけど、
せっかくだからSlackのbot導入についても合わせ技で一緒に学んでしまおうという目的で。
いつものように備忘録。今回は新米の自分には非常に学びが多かった気がします。
というわけで、今回の実装でやりたい事は
・Qiitaの記事一覧をくれるAPIを叩きにいきます
・Slackからコマンドでbotを呼び出し、欲しい記事のジャンルを選択
・記事一覧からランダムで1つのURLを返してくれる感じのを想定します
前提
・Qiitaアカウントを持っている(一応)
・Googleアカウントも持っている(なければ作って)
・導入したいSlackワークスペースの管理者権限がある
ざっくり手順
- Slackbotを作成
- Qiitaでアクセストークンを取得
- GASでslashコマンド受け取り用のwebアプリケーション1を作成
- GASで選択肢ボタン受け取り用のwebアプリケーション2を作成
- slackとアプリケーションを連携
こんな感じになりますが、各工程も躓いたところをピックアップし、他あっさり行きます。
詳しく知りたい方は参考にした記事を貼っておくので、そちらもご覧あれ。
##1. まずはSlackbotを作成
導入したいワークスペースにログインした状態でslackapiにアクセスし、
Create New App
からbotを作成します。
Permissions
以下の権限を設定します。
・chat:write
・chat:write.public
App Display Name
App Home
から App Display Name
を設定します(適当で良いです)
Display Information
Basic Information
の下の方で設定出来ます。botの見た目はここで(重要)
Verification Token
App Credentials
に書いてあります。
webアプリケーション作成の工程で使用するので控えておきましょう。
##2. Qiitaでアクセストークンを取得
Qiitaにログインした状態で、
設定のアプリケーションから、個人用アクセストークンを発行します。
一度発行したトークンは確認出来なくなるので、これも控えておきましょ。
##3. GASでslashコマンド受け取り用のwebアプリケーション1を作成
Googleドライブから新規でGASを開いたら、
まずはスラッシュコマンドの受けを作ります。
function doPost(e) {
const SLACK_TOKEN = 'トークン入れてね'; // Verification Tokenで取得したトークン
// 指定したチャンネルからの命令しか受け付けない
if (SLACK_TOKEN != e.parameter.token) {
throw new Error(e.parameter.token);
}
// 返答データ
var data = {
"text": "「いっちょAPIを叩いて、欲しい情報を持ってきますぜ」", //通常メッセージ
"response_type":"ephemeral",
//アタッチメント部分
"attachments": [{
"title": "Qiitan君に指示して下さい",// アタッチメントタイトル
"text": "Please select a task.",//アタッチメント内テキスト
"fallback": "hogehoge",//ボタン表示に対応してないクライアント向けメッセージ.
"callback_id": "callback_button",//これ書かないと動かないよ
"color": "#7fff00", //アタッチメントの棒の色を指定
"attachment_type": "default",
// ボタン部分
// ちなみにボタンは最大5つまでしか設定出来ないよ
"actions": [
{
"name": "books",
"text": "技術書関連の記事を検索",
"type": "button",
"value": "books"
},
{
"name": "Ruby",
"text": "Ruby on Rails関連の記事を検索",
"type": "button",
"value": "Ruby"
},
{
"name": "php",
"text": "php laravel関連の記事を検索",
"type": "button",
"value": "php"
},
{
"name": "infrastructure",
"text": "インフラ関連の記事を検索",
"type": "button",
"value": "infrastructure"
},
]
}]
};
return ContentService.createTextOutput(JSON.stringify(data)).setMimeType(ContentService.MimeType.JSON);
}
ポイント
・ Verification Token
を設定しましょ。
・ callback_id
は忘れずに。
<!DOCTYPE html><html><head><link rel="shortcut icon" href="//ssl.gstatic.com/docs/script/images/favicon.ico"><title>Error</title><style type="text/css">body {background-color: #fff; margin: 0; padding: 0;}.errorMessage {font-family: Arial,sans-serif; font-size: 12pt; font-weight: bold; line-height: 150%; padding-top: 25px;} (略
こんなの出たらちゃんとGASからslackに返ってきていないって事なのですが、デバッグが難しいですよね。自分の場合ですが、slackブラウザ版の検証モードを使いました。その時はcallback_id
ないよってエラーが出てたので、直ぐ解決出来ました。
公式ドキュメントのAttaching interactive message buttonsの部分にもcallback_id
ないとダメよと書いてありました。反省します。
※この時点ではまだ連携が完成してないからそもそもデバッグ出来ないけどね
Cuurent web app URL
webアプリケーション1のコードはこれで完成なので、デプロイします。
デプロイしたら、slackのSlash Commands
のRequest URL
にデプロイしたCuurent web app URL
を貼り付けます。
ついでにコマンドも好きな物を設定しましょう。ここで設定したコマンドでwebアプリケーション1をリクエストする構図です。
4. GASで選択肢ボタン受け取り用のwebアプリケーション2を作成
次に選ばれた選択肢を元にQiita APIを叩いて、記事のURLを返す部分を作ります。
function doPost(e) {
// ペイロード部分の取り出し
var payload = JSON.parse(e["parameter"]["payload"]);
var name = payload["actions"][0]["name"];
var value = payload["actions"][0]["value"];
const QIITA_TOKEN = 'トークンを入れてね';
//APIヘッダ
var headers = {'Authorization' : 'Bearer ' + QIITA_TOKEN};
var params = {'headers' : headers};
switch (name) {
case 'books':
var api_endpoint = 'https://qiita.com/api/v2/items?page=*&per_page=*&query=技術書';
break;
case 'Ruby':
var api_endpoint = 'https://qiita.com/api/v2/items?page=*&per_page=*&query=Ruby';
break;
case 'php':
var api_endpoint = 'https://qiita.com/api/v2/items?page=*&per_page=*&query=php';
break;
case 'infrastructure':
var api_endpoint = 'https://qiita.com/api/v2/items?page=*&per_page=*&query=インフラ';
break;
}
// APIを叩いてパースする
var response = UrlFetchApp.fetch(api_endpoint, params);
var json = JSON.parse(response.getContentText());
//ランダムにするよー
var a = Math.floor( Math.random() * 好きな数 );
// 返答する文章を整形
var url = json[a]['url'];
var title = "タイトル:" + json[a]['title'];
var text = title + "\n" + url;
var quest_attachment = {
"text": text,//アタッチメント内テキスト
"fallback": "hogahoga",
"callback_id": "callback_button",
"color": "#7ABB33",
"attachment_type": "default",
}
var rep = {
"text": "「お待たせしました!」",
"attachments": [
quest_attachment
]
};
return ContentService.createTextOutput(JSON.stringify(rep)).setMimeType(ContentService.MimeType.JSON);
};
叩くAPIはGET /api/v2/itemsです。
対象としたいページ数、要素数等は別途設定して下さい。
検索オプションはQiita Supportを見て、query=
以下にぶち込んでもらえればと思います。
URLエンコーダーも貼っておきます。
書けたらこちらもデプロイしましょう。
ポイント(というか失敗談)
最初はIncoming Webhooks
で、slackへpostする方法で進めていたのですが、
その場合、何かreturnしないと怒られてしまうのと、空データを返した場合、選択肢を表示しているbotコメントがそのまま残り続けてしまう(上書きされない)ので、素直にreturnする事としました。
5. slackとアプリケーションを連携
slackapiに戻って、Add features and functionality
からInteractive Components
に進み、Interactivity
をオンにして、デプロイしたwebアプリケーション2のURLをRequest URL
に貼り付けます。
ラストはInstall App to Workspace
からワークスペースへのbot導入を許可すれば完成です。チャンネルの指定も必要になると思います。
これでスラッシュコマンドを打つと
botを呼び出せます。
ジャンルを選択します。
上手く表示出来ました。検索が手抜きとか少し冗長なところもありますが、調べながらでなんやかんや記事の作成含め1日がかりで御座いました。勉強になりました。
参考にした記事
・[GAS]Slackのbotを作る方法を、お節介なほど丁寧に説明
・GASでQiita APIを使ってView・いいね・ストック数の一覧を取得する
・Slack API attachmentsチートシート
・Slack Interactive Messageリファレンス
あとは全部公式ドキュメントで解決しました。