GAS + TypeScriptでLINEに通知を送る方法を紹介します

@Panda_Program

時代はサーバレスへ

以前、PHPでLINE NotifyのAPIを叩くプログラムを書きました。

関連記事: GASをclasp(CLIツール)+ TypeScriptでローカルで開発する

この時はPHPファイルをレンタルサーバーに置き、cronで定期実行させていました。

しかし、時代はサーバレスです。APIを叩くだけならGoogle Apps ScriptやAWS LambdaといったFaaSで実現できます。

今回はTypescriptを学びたかったので、claspを使ってGoogle Apps Scriptにデプロイすることにしました。claspを使うと、webpackなどの設定が不要になり、気軽にTypescriptのコードを書くことができます。

claspの主なコマンド

開発中に使う主なclaspコマンドは以下です。

$ clasp login  // script.google.comにログインする
$ clasp create // プロジェクトを作成する
$ clasp push   // tsファイルのコンパイルとGASにアップロード
$ clasp open   // 該当のGASのページをブラウザで開く
$ clasp deploy [Version] [Description] // バージョンを管理できる

claspについては下記の記事が詳しいです。

GAS のGoogle謹製CLIツール clasp

コードを書く

const properties = PropertiesService.getScriptProperties()
// APIトークンは下記ページから発行する。通知を投稿するチャンネルを選択すればトークンが発行される。
// https://notify-bot.line.me/ja/
const TOKEN = properties.getProperty('LINE_NOTIFY_TOKEN')
const FROM = new Date(properties.getProperty('FROM'))
const ENDPOINT = 'https://notify-api.line.me/api/notify'
const MILLISECONDS_OF_DAY = 86400000
const DAYS_OF_YEAR = 365
// スタンプのIDは下記アドレスに記載
// https://devdocs.line.me/files/sticker_list.pdf
const STAMPS = [
    608, // プレゼントボックス
    301, // カクテル
    269, // ハート
    268, // 虹
]

function getHeaders(): { [key: string]: string } {
    return {
        "Content-Type": "application/x-www-form-urlencoded",
        "Authorization": `Bearer ${TOKEN}`
    }
}

function getStampNumber(): number {
    const length = STAMPS.length
    const random = getRandomInt(length)
    return STAMPS[random]
}

function getRandomInt(max: number): number {
    return Math.floor(Math.random() * Math.floor(max));
}

function getPayload(): string {
    const params = {
        'message': getMessage(),
        'stickerPackageId': 4,
        'stickerId': getStampNumber()
    }

    let body = [];
    Object.keys(params).map(key => {
        body.push(key + '=' + encodeURI(params[key]));
    })
    return body.join("&")
}

function getMessage(): string {
    const now = new Date()
    const diff = getDayDiff(now)
    const [years, days] = getYearsAndDays(diff)
    return createMessage(diff, years, days)
}

function getDayDiff(now: Date): number {
    const diff = (now - FROM) / MILLISECONDS_OF_DAY
    return Math.floor(diff)
}

function getYearsAndDays(diff: number): Array<number> {
    const years = Math.floor(diff / DAYS_OF_YEAR)
    const days = diff - DAYS_OF_YEAR * years
    return [years, days]
}

function createMessage(diff: number, years: number, days: number): string {
    return `
🎉おめでとう🎉
二人が付き合ってから
${diff}日が経ちました😍
今日で${years}年と${days}日です💕
これからもよろしくね😘`
}

function send(): void {
    const options = {
        "method": "POST",
        "headers": getHeaders(),
        "payload": getPayload(),
        "muteHttpExceptions": true
    }
    Logger.log(options);
    const res = UrlFetchApp.fetch(ENDPOINT, options);
    Logger.log(res.getContentText());
}

GASのメリット

APIのトークンを「プロジェクトのプロパティ」に記述できるため、誤ってトークンが流出することを避けられる。

GASのプロパティ設定画面

PropertiesService.getScriptProperties().getProperty('KEY名')で値を取得する。FROMは2019-04-01のようにYYYY-MM-DDで定義する。

claspのメリット

  • ES6の構文が使える
  • テンプレートリテラルが使え、文字列の連結を多用せずに済む
  • Typescriptを学ぶことができる
  • GitHubでのコードの管理が楽
    • もしclasp pushがなければ、ローカルで書いたコードをGASにコピペするため煩雑
  • 今回は不使用だが、Class構文も使える

結果

PHPからGAS+Typescriptへ載せ替えができました!

GASのプロパティ設定画面

Happy Coding 🎉

パンダのイラスト
パンダ

記事が面白いと思ったらツイートやはてブをお願いします!皆さんの感想が執筆のモチベーションになります。最後まで読んでくれてありがとう。

  • Share on Hatena
  • Share on Twitter
  • Share on Line
  • Copy to clipboard