0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Slack上に外部APIを利用したBotを作成したい

Last updated at Posted at 2025-01-06

はじめに

現業務にてチーム内の非エンジニアメンバーからGoogleMaps APIからの情報を簡単に取得できるようなツールがほしいとのニーズがあったため作成方法の備忘メモを残しておく。

What is this?

設定手順

1. Places APIの有効化とトークン発行

  • Google Cloudにアクセスし、「APIとサービス」に移動する
  • 「+APIとサービスを有効にする」を押す
  • Places APIを検索し選択 > 有効化
    • image.png
  • APIとサービスにて「鍵と認証情報」に移動する
  • 「+認証情報を作成」> 「APIキー」を選択
  • 作成されたキーを保存する
    • 後続のGASにて設定する
  • memo: キーの制限やAPIの制限については一旦デフォルトのままとした
    • image.png

2. Slack App作成

  • Slack apiにアクセスし、Your appsに移動する
  • 「Create New App」を押す
    • 「From scratch」を選択する
    • App Nameにアプリの名前を入れる
    • Pick a workspace...にてデプロイしたいSlackのワークスペースを選択する
    • 「Create App」を押す
    • image.png
  • 必要に応じてBasic Information情報を入力する(アイコン画像や概要など)
  • Verification Tokenを控えておく
    • 後続のGASにて設定する
  • (左メニュー) Features内のOAuth & Permissionsに移動する
  • Scopesの項目にて下記Bot Token Scopesの設定を行う
    • commandsを追加
    • image.png

3. Google Apps Scriptのデプロイ

  • Apps Scriptにアクセスし「+新しいスクリプト」を押す
    • 必要に応じてプロジェクト名を設定する
  • (左メニュー) プロジェクトの設定に移動する
    • image.png
  • スクリプトプロパティに下記を追加する
    • プロパティ名: GOOGLE_API_KEY
      • 値:手順1にて取得したPlaces APIのキー情報
    • プロパティ名: SLACK_VERIFICATION_TOKEN
      • 値:手順2にて取得したVerification Token情報
    • image.png
  • (左メニュー) エディタに移動する
  • コード.gsに下記をコピペ
    function doPost(e) {
      const scriptProperties = PropertiesService.getScriptProperties();
      const SLACK_VERIFICATION_TOKEN = scriptProperties.getProperty("SLACK_VERIFICATION_TOKEN");
      const GOOGLE_API_KEY = scriptProperties.getProperty("GOOGLE_API_KEY");
    
      // URLエンコード形式のデータを解析
      if (!e || !e.parameter) {
        return ContentService.createTextOutput("Invalid request: No parameters found.")
          .setMimeType(ContentService.MimeType.TEXT);
      }
    
      const params = e.parameter;
    
      // Slack Verification Tokenチェック
      if (params.token !== SLACK_VERIFICATION_TOKEN) {
        return ContentService.createTextOutput("Unauthorized").setMimeType(ContentService.MimeType.TEXT);
      }
    
      const input = params.text.trim(); // ユーザー入力を取得
      let placeData;
      let errorMessage = null;
    
      try {
        if (input.includes(",")) {
          // 緯度・経度の場合
          const [lat, lng] = input.split(",").map(Number);
          if (isNaN(lat) || isNaN(lng)) throw new Error("Invalid coordinates format.");
          placeData = getPlaceDataByCoordinates(lat, lng, GOOGLE_API_KEY);
        } else {
          // 場所名の場合
          placeData = getPlaceDataByName(input, GOOGLE_API_KEY);
        }
      } catch (error) {
        errorMessage = error.message || "An error occurred.";
      }
    
      const response = {
        response_type: "in_channel", // 公開応答
        text: errorMessage
          ? `Error: ${errorMessage}`
          : placeData
          ? `Name: ${placeData.name || "建物名称が利用できません"}\nPlace ID: ${placeData.placeId}\nAddress: ${placeData.address}`
          : "No place found.",
      };
    
      return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);
    }
    
    // 緯度・経度からPlace ID、住所、建物の名称を取得
    function getPlaceDataByCoordinates(lat, lng, apiKey) {
      const url = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${lat},${lng}&radius=1&key=${apiKey}&language=ja`;
      const response = UrlFetchApp.fetch(url);
      const data = JSON.parse(response.getContentText());
    
      if (data.results && data.results.length > 0) {
        const result = data.results[0];
        return {
          name: result.name || "建物名称が利用できません", // 建物の名称
          placeId: result.place_id,
          address: result.vicinity || "住所情報が利用できません", // 日本語住所
        };
      }
      return null; // 見つからない場合
    }
    
    // 場所名からPlace ID、住所、建物の名称を取得
    function getPlaceDataByName(name, apiKey) {
      const url = `https://maps.googleapis.com/maps/api/place/textsearch/json?query=${encodeURIComponent(name)}&key=${apiKey}&language=ja`;
      const response = UrlFetchApp.fetch(url);
      const data = JSON.parse(response.getContentText());
    
      if (data.results && data.results.length > 0) {
        const result = data.results[0];
        return {
          name: result.name || "建物名称が利用できません", // 建物の名称
          placeId: result.place_id,
          address: result.formatted_address || "住所情報が利用できません", // 日本語住所
        };
      }
      return null; // 見つからない場合
    }
    
    
  • 右上の「デプロイ」ボタンを押す > 「新しいデプロイ」を選択
  • 選択の種類の右側歯車マークから「ウェブアプリ」を選択する
  • 「アクセスを承認」を押す
  • Googleアカウントにログイン後、下記の画面が表示された場合は「Advanced」をクリックし、「Go to プロジェクト名」を選択、「Allow」ボタンを押す
    • image.png
  • デプロイが完了する
    • ウェブアプリURLを控えておく
      • 後続のSlackApp設定にて利用する

4. Slack Appにおけるコマンド設定

  • Slack apiにアクセスし、作成したアプリに移動する
  • (左メニュー) Slash Commandsに移動する
  • 「Create New Command」ボタンを押す
    • Command: /get_place_id (任意のコマンド名でok)
    • Request URL: 手順3にて作成したGASのウェブアプリURLをペースト
    • Short Description: 任意で記載(下記のような感じでSlack UI上で表示される)
    • Usage Hint: 任意で記載(下記のような感じでSlack UI上で表示される)
    • image.png
    • 右下の「Save」を押す
  • (左メニュー) 「Install App」に移動する
  • 「Install to ワークスペース名」を押す

動作確認

  • Slackの任意のチャンネル or 自分へのDM等にて下記コマンドを実行してみる
    • /get_place_id 大手町プレイスウエスト
    • プレイスIDが返却されたら成功
    • image.png
  • うまく返ってこない場合はGAS上の設定やSlack apiの設定を見直す

おわりに

GASとSlack apiを用いることでサーバレスで簡単にbotが作成できるので今後も活用したい。

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?