5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Opt TechnologiesAdvent Calendar 2018

Day 21

SlackのRTM APIを使った開発のハマりどころやつらみ

Posted at

主に SlackをTwitterのタイムラインライクに閲覧できるクライアント を作ったときにハマった話を書きます。


この記事はオプトテクノロジーズアドベントカレンダー21日目のエントリーです。

20日目は @yorishigeito さんの「開発合宿でIoTした」です
22日目は @hey_cube さんの「Storybook + zisui + reg-suit な visual testing を構築する」です


前提

アプリ要件

  • Slackのメッセージをほぼリアルタイムに受け取って表示したい
  • アプリ入れさせたくないのでwebサービスとして提供したい

以上の要件を満たすためにRTM APIを選択
Event APIという線もあったが、ngrok使ったりして開発するの地味に面倒そうだった(と思って試さなかったのがもしかしたら大失敗だったかも)

ハマり・つらみ

ハマり

  • @slack/clientの RTM API実装がnodeじゃないと動かない
  • OAuth Scopeの clientidentity.basic を同時に許可する事ができない
  • passport.jsのslackプラグインで使い物にならないものが乱立している

つらみ

  • rtm.startエンドポイントの API rate limitが少なすぎる
  • @slack/clientRTMClient#startでコネクション確立中に再度コネクション確立要求をすると例外を吐く
  • slackのテキストパーサー・コンバータがない
  • APIの仕様にドキュメントが追いついてない
  • そもそもSlackを再実装するのが大変

解説していきます

@slack/clientの RTM API実装がnodeじゃないと動かない

まんまです。
これが理由で、なんらかのnode.jsが動くバックエンド実装が必要になってしまう
実際はelectronを使うかnodeでサーバーを立てるかの2択。
EventAPIを使っていたとしてもサーバーが必要になるので、どちらにせよフロントエンドで完結出来ないので手軽でない。。

OAuth Scopeの clientidentity.basic を同時に許可する事ができない

アプリを実際に使うにあたって、ユーザーはOAuthの認可フローを通す必要がある(ユースケースによってはSlack Button を利用することで省略も可能)。

このときに、RTM APIを使うのに必要な client という権限と、自分自身のユーザー情報を取得するのに必要な identity.basicという権限を同時に認可しようとするとSlackに以下のようなエラーメッセージと共に突っ返される

Invalid permissions requested
Cannot request object scopes with deprecated scopes

ss_ 2018-12-25 22.22.53.png

ドキュメントからの推測しかできないが、おそらく Scopeのページlegacy ラベルが張られている権限はその他のstableな権限と同時にリクエスト出来ないのではないかと予想される(実際試してみると client , adminのような組み合わせは通る)

この問題が解決できないと、ユーザーがアプリを動かすに至れないのでなんとかする必要があったが、どこにも情報がなかったのでかなり苦労した。
実際に作ったアプリでは、「 identity.basicの権限を許可する」というフローのあとに、「 clientの権限を許可する」というフローを踏ませるワークアラウンドでなんとかした
これがほんとの二段階認証!

実際の動きはこんな感じ。最悪のUX。
https://gyazo.com/84cf702b999d7ac65c60f3f62e511210

passport.jsのslackプラグインで使い物にならないものが乱立している

気をつけましょう・・・
passport.jsでOAuth認可フローを実装する場合、大抵 passport-(サービス名) という名前のライブラリを使うことになるが、 passport-slackは普通にバグっていて動かない上にメンテもされていないという状態になっている。
(普通に認可するだけだといいが、二段階認証(違う)を実装する都合でバグを踏んだみたいなのもあり・・・)

最終的には passport-slack-oauth2を使って動かせたのでよかったものの、結構辛かった・・・

rtm.startエンドポイントの API rate limitが少なすぎる

rate limitがひどく低く、1分間に数回でlimitになる ( https://api.slack.com/methods/rtm.start )
またこれはあとから気づいたことだけど、SlackAPIはOAuthトークンごとのlimitではなく、ワークスペース単位のlimitなので、誰にでも使えるサービスとして提供するのに耐えられない(致命的)
https://api.slack.com/docs/rate-limits#overview

今回作ったアプリは、アプリのサーバーがユーザーごとにSlackとのコネクションを作り、リアルタイムにメッセージを受け取る形をとっている。
そのためnodeサーバーが再起動したときには、その時点で接続していたユーザーのコネクションを全て再接続したいところだが、それを安直にやるとrate limitに引っかかってしまう。つらい(つらい
ちなみにこの問題は時間がなかったので未解決・・・

@slack/clientRTMClient#startでコネクション確立中に再度コネクション確立要求をすると例外を吐く

例えば「とあるユーザーがこのアプリを使い始めて、認可フローを終えてアプリに戻ってきたタイミング(=初めてアプリのサーバーがSlackとコネクションを確立するタイミング)で、コネクションが成立する前にブラウザをリロードする」みたいな状況で死ぬ

しかもこの場合、ユーザー的にはあとからの接続要求が通ってほしいが、サーバーとしてはあとから来たほうで例外が出るのでフロントにコネクション成立した状態で返せないという状態になる(アプリの作りも悪いとは思う)
また、 RTMClientはコネクション確立中というステータスを取れないので、回避もままならない。例外をcatchしてもポーリングするしかなくて、先述したrate limitも相まって非常に難解な問題だった(なお未解決。。。

slackのテキストパーサー・コンバータがない

そのまんま。
markdownライクなあの記法をちゃんと解釈してhtmlにしたいけど、それを実現するライブラリがなさそう(あったら教えてください)

たとえばSlackの取り消し線は ~文字列~だが、これを 文字列 のように変更するという実装が簡単にできない。
一応ドキュメントは あるが、実装するのが大変・・・

APIの仕様にドキュメントが追いついてない

つらい。ドキュメント書くのは大変だからしょうがないという気持ちもありつつ。。。

たとえば messageイベントのドキュメントでは解説されていないメッセージがバンバン飛んでくるので色んなメッセージを叩いてがんばりましょうという感じ。
botやアプリ連携で投稿されるCircleCIなどの投稿が代表(だったと思う)

そもそもSlackを再実装するのが大変

当たり前。
クライアント作ってみて思ったが、Slack社はすごい。すごい!!

おわりに

つらかった(小並感)

5
0
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
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?