重要なおしらせ (2020/06/19)
Yahoo! JAPAN さんの API 提供が 2020/10/31 で終了となるようです。
こちらの記事で紹介しているサンプルコードはそれ以降の動作を保証いたしません。もし代替案をサジェストしてくださる方がいれば、こちらのリポジトリに issue 登録、または pull request をお待ちしております。何らかの方法で対応できた場合はこの記事も更新します。
そろそろ梅雨明けですが・・
そろそろ今年も、ほぼ全ての地域が梅雨明けしそうな頃合い1ですが、いかがお過ごしでしょうか?
先日、Twitter でこちらの投稿を見かけまして、確かにこれは便利な Slack 連携だと思いました。
東京アメッシュをSlackに流す的なのがうらやましかった。
— しゃある🐰 (@sharlm) July 19, 2019
たまたま雨が降ってきたので見てたら「ん?これは?」となったので昼休みに実装してみた。できたー! pic.twitter.com/eU1A26zSfS
「東京アメッシュをSlackに流す的なのがうらやましかった」と書かれているので、すでにそのような Slack アプリをつくって普段から利用されている方がいらっしゃるのでしょう。素晴らしい Slack API の活用例ですね!
試しにつくってみた
アニメーション GIF になるバージョンをつくってみました。雨雲レーダーってこれから雨が降りそうかを正確に判断できるだけでなく、ずっと見ていられる感じもあって、眺めているのも楽しかったりしますよね

スラッシュコマンドからのリクエストの処理には Slack が最近公開した Bolt ⚡️ という新しいフレームワークを利用して実装しています。Bolt については、以下の日本語の情報をご覧ください。
実装したアプリは以下の GitHub リポジトリで公開しています。
git.io/amesh
という短縮 URL もつくっておいたので、他の人に教えるときはぜひそちらで!
今回対応してみた三つの機能
まず、この Slack アプリがどのように動くものなのか、完成形を見てみましょう。この Slack アプリの基本的な挙動は、スラッシュコマンドで呼び出すと Slack アプリが Yahoo! JAPAN の API から日時をスライドしながら複数枚の画像を取得して、それを一つのアニメーション GIF として応答するというものです。
デフォルトの表示 - /amesh {prefecture}
デフィルトでは、アルファベットの都道府県名(例: tokyo, osaka, aichi)を受け取ると、今の雨雲レーダーから少し先の予測までをアニメーション GIF で表示します。引数指定なしは東京都(tokyo)で動作します。

今の状況だけを表示 - /amesh {prefecture} now
アニメーション GIF ではなく、今時点での雨雲レーダーだけを表示したい場合は now
をつけます。画像一枚だけの取得ですし、応答がはやくなります。

直近一日分を表示 - /amesh {prefecture} today
三つ目のオプションは、直近一日の雨雲の流れを見るための today
オプションです。これはこれから雨が降るかどうか知りたいというよりは、大雨の日などにどの時間帯が一番ピークだったか、後から振り返るときなどに使うとよさそうですね。

コードを変えずにカスタマイズ
私が作ったこのアプリのコードを変えることなく、カスタマイズしたい場合、以下の二点を変更することができます。
スラッシュコマンド名
デフォルトは /amesh
ですが、SLASH_COMMAND_NAME
という環境変数に別の名前を指定して Slack アプリの設定側でも同じ名前を指定すれば、変更することができます。
マップの表示モード
デフォルトは map
という設定ですが、Yahoo! JAPAN の API には以下のようなオプションがあります。変更する場合は YAHOO_JAPAN_API_MAP_MODE
という環境変数に設定してください。
-
map
- 通常の地図 -
photo
- 航空写真 -
map-b1
- 地下街 -
hd
- ハイビジョン地図 -
hybrid
- ハイブリッド地図 -
blankmap
- 白地図 -
osm
- Open Street Map
ローカルで動かしてみよう
事前に Slack アプリの設定が必要です。まだ作成していない場合は https://api.slack.com/apps にアクセスして「Create New App」ボタンから新しい Slack アプリを作ってください。
Slack アプリの設定
Slack アプリをつくったら、アプリの設定画面で以下の設定や情報の取得を行います。
スラッシュコマンドを追加する
左メニューの「Features > Slash Commands」から設定できます。
デフォルトの設定で OK なら /amesh
という名前でコマンドを追加、Request URL はデプロイ予定の URL を入力します。まだ URL が決まっていない場合はダミーで入れておいてあとで変更することもできます。
ボットユーザーを追加する
左メニューの「Features > Bot Users」から設定できます。
名前はなんでも OK です。
必要な権限(scope)を設定する
左メニューの「Features > OAuth & Permissions」から設定できます。
この手順でやっていれば、すでに commands
と bot
は付いていると思いますので、追加で files:write:user
を指定します。
アプリをワークスペースにインストールする
左メニューの「Settings > Install App」から実行できます。
インストールが終わったら、発行された「Bot User OAuth Access Token」を SLACK_BOT_TOKEN
の環境変数の値として使います。また左メニューの「Settings > Basic Information > App Credentials」の「Signing Secret」を SLACK_SIGNING_SECRET
の値として使用します。
Yahoo! デベロッパーネットワークの設定
Yahoo! デベロッパーネットワークにアクセスして、Yahoo! JAPAN の Web API を活用するアプリケーションの設定を行います。追加手順はこちらで確認することができます。

「サーバーサイド(Yahoo! ID連携 v2)」のアプリケーションを作成して、発行された「Client ID」を YAHOO_JAPAN_API_CLIENT_ID
として使用します。
ローカルで動作確認する
Node.js を使った開発に慣れていれば、ローカルで動かしてみてください。Bolt はこの記事時点で Node 10.13.0 以上で動作するので、サポートされている Node.js をインストールしておいてください。そして必要な環境変数は _env
というファイルにサンプルがあるのでそれらを指定してください。
nvm use 10.13.0 # Bolt runs on Node 10.13+
cp -p _env .env
vi .env
source .env
その上で必要な npm モジュールをインストールして、アプリを起動してみてください。
npm i
npm run local
上記でアプリが正常に起動しましたか? この Node アプリは http://localhost:3000/slack/events
で Slack からのリクエストを処理するよう設定されています。
さらに、もう一つ Terminal ウィンドウを開きます。ngrok という開発用プロキシを使って、この Node アプリが Slack プラットフォームからのリクエストを受け付けられるようにします。
ngrok http 3000
表示された URL を Slack アプリの設定画面の「Features > Slash Commands」に設定したスラッシュコマンドの「Request URL」に設定します。
npm run local
はコードが変更されると自動的に反映されるように設定されているので、コードをいじっては /amesh
コマンドで呼び出すというサイクルで試行錯誤ができます。色々と試してみてください。
例えば Yahoo! API の z
パラメータを変更すれば、より広域な地図に変更して日本全体の雨雲の流れを表示してみたりもできます。

もう少し実用的にするために、会社のオフィスの緯度・経度を基準点に指定して、パラメータを指定しなくても簡単にオフィスの近辺での情報を表示するように変更して運用するとよいかと思います。
また、スラッシュコマンドではなく bot メンションや、キーワードへの反応に変更するなどのカスタマイズも Bolt なら簡単にできるでしょう。メンションされたときの動作は app.event('app_mention', ...)
、キーワードへの反応は app.message('雨雲レーダー見せて', ...)
のように実装できると思います。
再掲となりますが、以下のドキュメントも参考にしてみてください。
デプロイしよう
通常の Bolt アプリであれば、どのような環境にも非常に簡単にデプロイが可能です。Heroku だけでなく、AWS API Gateway + Lambda や Google Cloud Functions (Cloud Functions for Firebase も同様)など、様々な環境で Bolt は簡単に動作させることができます。2
しかし、今回のサンプルに限っては node-canvas に依存している事情から AWS Lambda で動かすのはなかなか手間がかかります(詳細は注釈参照)3。この手のアプリは Docker image を作って別の仕組みでで動かすのがよさそうです。
また、Google Cloud Functions / Cloud Functions for Firebase については AWS Lambda のようにネイティブ npm モジュールについての制限は特になく、簡単に動作はさせられますが、今回のように外部 URL への HTTP リクエストを複数投げてアニメーション GIF をつくるような処理はあまり相性がよくないようで、どうしても応答までに長く時間がかかってしまうようでした。そのため、今回、以下に示す例は一枚のみの天気図を表示するサンプルとしました。
ということで、今回のサンプルをそのまま動かすなら Heroku が最も簡単かと思います。
Heroku にデプロイする
この GitHub リポジトリは Deploy to Heroku
ボタンが設置されています。Heroku のアカウントをお持ちなら、今すぐにでも簡単に Heroku にデプロイすることができます。

いかがでしたか?簡単に動作させることができたのではないかと思います。
FaaS にデプロイする
Heroku に比べるとシンプルなサンプルとなりますが FaaS へのデプロイについても紹介しておきます。
Cloud Functions for Firebase
Google Cloud に関しては Cloud Functions fore Firebase のサンプルを紹介しています。若干の違いはありますが4 Google Cloud Functions でも同様にデプロイできるはずです。
AWS API Gateway + Lambda
AWS API Gateway + Lambda のサンプルは Serverless Framework を使ったサンプルです。
AWS のサンプルは以下の二つの問題に対処するために少し工夫をしています。
- 同期的に処理をすると特にコールドスタート時に 3 秒以内に応答できずにタイムアウトしてしまう
- Lambda の handler が応答を返した後にまだ処理中の Promise での非同期処理が打ち切られてしまう
以下は Lambda functions の定義からの抜粋です。API Gateway 経由で Internet facing な frontend
と内部からのみ呼び出される backend
の二つの Lambda を定義しています。
functions:
# frontend: Slack からのリクエストを受け付けて backend を起動し 3 秒以内に 200 OK を返す
frontend:
handler: handler.frontend
events:
- http:
method: post
path: /slack/events
# backend: frontend 関数によって非同期実行され、時間がかかる処理を行う
# エラーが発生したら Slack からもらった response_url に通知する
backend:
handler: handler.backend
frontend
は Slack Platform からのリクエストを受け付けます。frontend
は、無事 backend
を非同期で起動できたら HTTP リクエストに対して 200 OK を返して終了します。
backend
は処理を実行し、エラーが発生した場合には response_url
を使ってエラーを通知します。 スラッシュコマンドでの response_url
についてはこちらのドキュメントを参照してください。
まとめ
このように Yahoo! JAPAN さんが公開している API を利用すれば、非常に簡単に雨雲レーダーを反映した地図画像を取得することができます。この記事ではそれを複数枚つなぎ合わせてアニメーション GIF をつくり、さらにそれを Slack にファイルとしてアップロードするサンプルをご紹介しました。
そして、その実装は Bolt を活用しました。Bolt を使うと Slack アプリ固有の処理をするコードを最小化して、本質的な実装だけに集中することができるようになります。日本語に翻訳されていますので、入門ガイドを読んでみてください。
ぜひ皆さんの職場やコミュニティのワークスペースでこのスラッシュコマンドを有効にして活用してみてください
-
いくつか個人的にサンプルを書いたりもしているので、見てみてください。 ↩
-
興味のある方は node-canvas の AWS Lambda に関するドキュメントと関連する GitHub issueを見てみてください。簡単に説明すると、今回の場合、 macOS などでパッケージングした zip パッケージは Lambda 上で動作しないため AWS の EC2 環境などで
sls deploy
する必要があります。が、それを行っても、なおlibuuid.so.1
が Lambda 環境だと存在しなくて動作しないため、Lambda Layers を使って対応しなければならないようです。 ↩ -
関数を export するときに
functions.https.onRequest
を呼ぶかなどの軽微な違いです。 ↩