【JavaScript】Qiita APIをGASで叩いてくるbotをSlackに導入してみた

APIの学習がきっかけではあったのだけど、
せっかくだからSlackのbot導入についても合わせ技で一緒に学んでしまおうという目的で。
いつものように備忘録。今回は新米の自分には非常に学びが多かった気がします。

というわけで、今回の実装でやりたい事は
・Qiitaの記事一覧をくれるAPIを叩きにいきます
・Slackからコマンドでbotを呼び出し、欲しい記事のジャンルを選択
・記事一覧からランダムで1つのURLを返してくれる感じのを想定します

## 前提
・Qiitaアカウントを持っている（一応）
・Googleアカウントも持っている（なければ作って）
・導入したいSlackワークスペースの管理者権限がある

## ざっくり手順
1. Slackbotを作成
2. Qiitaでアクセストークンを取得
3. GASでslashコマンド受け取り用のwebアプリケーション1を作成
4. GASで選択肢ボタン受け取り用のwebアプリケーション2を作成
5. slackとアプリケーションを連携

こんな感じになりますが、各工程も躓いたところをピックアップし、他あっさり行きます。
詳しく知りたい方は参考にした記事を貼っておくので、そちらもご覧あれ。

##1. まずはSlackbotを作成
導入したいワークスペースにログインした状態で[slackapi](https://api.slack.com/apps)にアクセスし、
` Create New App` からbotを作成します。

### Permissions
以下の権限を設定します。
・`chat:write`
・`chat:write.public`

### App Display Name
`App Home` から `App Display Name`を設定します（適当で良いです）

### Display Information
`Basic Information`の下の方で設定出来ます。botの見た目はここで（重要）
![スクリーンショット 2020-09-12 22.53.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531606/e25a996b-b6a6-3ecc-8784-139fa0dcfc74.png)

### Verification Token
`App Credentials`に書いてあります。
webアプリケーション作成の工程で使用するので控えておきましょう。

##2. Qiitaでアクセストークンを取得
[Qiita](https://qiita.com/)にログインした状態で、
設定のアプリケーションから、個人用アクセストークンを発行します。
一度発行したトークンは確認出来なくなるので、これも控えておきましょ。

##3. GASでslashコマンド受け取り用のwebアプリケーション1を作成
Googleドライブから新規でGASを開いたら、
まずはスラッシュコマンドの受けを作ります。

```javascript:コード1.gs
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` は忘れずに。
![スクリーンショット 2020-09-12 23.26.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531606/073b54b6-74b9-39c0-7ec9-0e03b0c744a5.png)

```
<!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](https://api.slack.com/legacy/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を返す部分を作ります。

```javascript:コード2.gs
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](https://qiita.com/api/v2/docs#get-apiv2items)です。
対象としたいページ数、要素数等は別途設定して下さい。
検索オプションは[Qiita Support](https://help.qiita.com/ja/articles/qiita-search-options)を見て、`query=`以下にぶち込んでもらえればと思います。
[URLエンコーダー](https://tech-unlimited.com/urlencode.html)も貼っておきます。

書けたらこちらもデプロイしましょう。

### ポイント（というか失敗談）
最初は`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導入を許可すれば完成です。チャンネルの指定も必要になると思います。

これでスラッシュコマンドを打つと
![スクリーンショット 2020-09-13 0.59.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531606/7c1c5128-5c20-ff76-99a4-6141ff3c24a8.png)
botを呼び出せます。
![スクリーンショット 2020-09-12 23.44.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531606/cd84aaea-84e3-4228-a288-4d02ceb0e081.png)
ジャンルを選択します。
![スクリーンショット 2020-09-13 1.03.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531606/f580fc57-1ea2-7b0d-16e4-860a959c6a25.png)
上手く表示出来ました。検索が手抜きとか少し冗長なところもありますが、調べながらでなんやかんや記事の作成含め1日がかりで御座いました。勉強になりました。

## 参考にした記事
・[[GAS]Slackのbotを作る方法を、お節介なほど丁寧に説明](https://qiita.com/sew_sou19/items/723feb39ea4aa7becfab)
・[GASでQiita APIを使ってView・いいね・ストック数の一覧を取得する](https://qiita.com/tksnino/items/7e6a587ff6e1817490ad)
・[Slack API attachmentsチートシート](https://qiita.com/daikiojm/items/759ea40c00f9b539a4c8)
・[Slack Interactive Messageリファレンス](https://qiita.com/hypermkt/items/b2ffaf610ac92235c4d6#%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3url%E3%83%AC%E3%82%B9%E3%83%9D%E3%83%B3%E3%82%B9)

あとは全部公式ドキュメントで解決しました。