しくじり日記

筋肉つけたい

Cloud Functions for Firebase でslackへの通知を定期実行する ~その2~

tossyisland.hatenablog.com

前回の続きです。 今回はGithubのトレンドを取得してSlackに通知する流れを書いていきます。

Githubのトレンドを取得

公式のAPIだけでトレンドを取得できるものはなかったので、npmのパッケージから探してみたところ以下のパッケージが良さそうでした。

www.npmjs.com

language(プログラミング言語)とperiod(daily or weekly)を指定して絞り込むこともできます。 ただ、ドキュメントやコードを追ったところ、レスポンスの返り値がunknow型となっているため、そのままではデータを扱うことができません。

const response = await trending();
console.log(response[0].author) // これはエラーになる

そのため、Type Guardを使って型を推論させることで、データとして扱えるようにしました。 プロパティ全ての存在チェックをするのはちょっと冗長とは思うのですが、もっと良い書き方が分かりませんでした...何かあれば追記しようと思います。

import trending from "trending-github";
type Repository = {
  name: string;
  href: string;
  description: string;
  language: string;
};
const isRepos = (repos: any): repos is Repository[] =>
  repos.every(
    (repo: Repository) =>
      repo.name != undefined &&
      repo.href != undefined &&
      repo.description != undefined &&
      repo.language != undefined
  );
export const getTrend = async () => {
  const response = await trending();
  const repos = isRepos(response) ? response : [];
  return repos;//Repository型に推論させることで、repo[0].authorなどが扱えるようになる
};
一応、Type assertionsで型キャストする方法でもコンパイルは通るのですが、それではせっかくの型がある言語を使う意味がないので、あまりよろしくないかと思います。
const repos = response as Repository[];

Slackに通知

TypeScript(JavaScript)を使ってSlackのメッセージを投稿するには、以下の二つのやり方があります。

api.slack.com

  • 直接WebAPIを叩く
    • @slack/web-api をインストール
    • 同じく、chat.postMessageメソッドを用いる
    • botTokenは不要

slack.dev

個人的に使ってみた所感としては、カスタムコマンドを作成したり、イベントとのフック(チャンネルに参加したメンバーがいた時〇〇するetc)を作成したりなど、拡張性を考えるとBoltに寄せる方が良いと思いました。 ただ、postMessage にtokenを与えなきゃいけないのがどうも違和感があり、今回はメッセージを投稿するのにはWebAPIの方を使っています。

import { WebClient } from "@slack/web-api";
export class slackBot {
  web: WebClient;
  constructor(web: WebClient) {
    this.web = web;
  }
  sendMessage = (channel: string, content: string) => {
    (async () => {
      await this.web.chat.postMessage({
        channel: channel,
        text: content,
      });
    })();
  };
}

(インスタンスの生成時とメソッドを呼ぶ際で、両方にtokenを与える必要があるのがどうも...)

ハマりポイント

作成したアプリを投稿させたいチャンネルに招待する必要があります。招待していない場合、チャンネルが見つからないと怒られてしまいます。

(node:14215) UnhandledPromiseRejectionWarning: Error: An API error occurred: not_in_channel
そんなの当たり前と思う方が大多数だと思いますが、自分はこれに気がつかず時間を溶かしてしまったので教訓として...

まとめ

ここまでで、目的であるGithubのトレンドを取得することと、それをSlackに定期的に通知することまでができました。最後に、英文を翻訳してから通知している部分について次回書いていきます。