【2022年改訂版】AizuHack LINEBot勉強会 Vol.1

# AizuHack LINEBot勉強会 Vol.1

## 資料一覧

- [LINEBotとは](https://docs.google.com/presentation/d/1U1vl67gJNOdO5in7H__jPXWieT3Lv0cFmv350AmAKHA/edit?usp=sharing)
- AizuHack LINEBot勉強会 Vol.1(本記事)
- [AizuHack LINEBot勉強会 Vol.2](https://qiita.com/shinbunbun_/items/4034e9c2c7553ed3107e)
- [AizuHack LINEBot勉強会 Vol.3](https://qiita.com/shinbunbun_/items/0dfc42584518dc60e3e7)
- [AizuHack LINEBot勉強会 Vol.4](https://qiita.com/shinbunbun_/items/43e2c486ac8839a6d32e)

## はじめに

こんにちは、会津大学学部二年のしんぶんぶんです。

本記事はAizuHackのLINEBot勉強会 Vol.1の資料になります。

本記事のサンプルコードは個人利用で一般的に使われるLINE Messaging APIの機能をだいたいカバーしており、サンプルコードを書き換えるだけでLINE Messaging APIのだいたいの機能が使えるようになっています。

LINEBotの入門記事やサンプルはたくさんありますが、その多くがオウム返しbotを作るだけやngrokで動かすだけの拡張性が低いものになっています。
AWSなどにデプロイする記事などもありますが、初心者には若干ハードルが高くとっつきにくいかと思います。
今回の資料では、初心者でも理解できるということを念頭におきつつ、例えば、Vercelでデプロイして永続化する、ソースコードはできるだけ改造しやすいように書くなど、できるだけ拡張性が高いように作成しました。
コピペだけで簡単に機能拡張できるようなサンプルコードになっています。

【追記】
最初からクラウドにデプロイすると手間がかかるため、最初はngrokで試して後からGCPのCloud Runへデプロイする形に変更しました。
GCPへのデプロイ手順は[AizuHack LINEBot勉強会 Vol.4](https://qiita.com/shinbunbun_/items/43e2c486ac8839a6d32e)に掲載しています。

また、本記事に掲載している解説の多くは[公式リファレンス](https://developers.line.biz/ja/reference/messaging-api/)を参考に作成しています。
このリファレンスは非常にわかりやすいため、作っていて何かわからないことがあったらリファレンスを参考にしましょう。

## できるようになること

<!-- - VercelにデプロイしてLINEBotを動かすことができる -->
- ngrokを使ってLINEBotを動かすことができる
- 一般的に使われるイベントの種類を理解できる
- LINE Messaging APIで返信できるメッセージの種類が理解できる

## サンプルコードについて

本サンプルコードで試せることは以下の通りです

- メッセージイベント
  - テキスト
  - 画像
  - 動画
  - 音声
  - ファイル
  - 位置情報
  - スタンプ
- 送信取消イベント
- フォローイベント
- フォロー解除イベント
- 参加イベント
- 退出イベント
- メンバー参加イベント
- メンバー退出イベント
- ポストバックイベント

## LINEBotについて

LINEBotについては[こちらのGoogle Slides](https://docs.google.com/presentation/d/1U1vl67gJNOdO5in7H__jPXWieT3Lv0cFmv350AmAKHA/edit?usp=sharing)で解説しています。

## 事前準備

この記事を読む前に以下の事前準備を行ってください。

- JavaScriptについて勉強する
- [LINE Developers](https://developers.line.biz/ja/)のアカウントを作成して、プロバイダを1つ作成する
  - 普段使っているLINEアカウントでログインしてください
- [ngrok](https://ngrok.com/)のアカウントを作成する
- （ローカルで開発したい人は）ローカルにNode.jsの環境を導入する

## 簡単な流れ

1. LINEBotのアカウントを作成する（Messaging APIのチャネルを作成する）
2. GitHubのリポジトリからソースコードをcloneして、モジュールをインストールする
3. LINE DevelopersからLINE Botの設定をする
<!-- 4. ローカルの環境にvercelのアカウントを紐づけて環境変数を設定する -->
4. ngrokで試してみる
5.  完成！

## 作ってみよう！

### 初回準備

1. [LINE Developers](https://developers.line.biz/ja/)にログインしてMessaging APIのチャネルを作成する
   - チャネル名とかは適当にいれる（LINEという単語が入っていると作成できないので注意）
2. [GitHubリポジトリ](https://github.com/shinbunbun/aizuhack-bot)からコードをcloneする
3. ソースコードがあるリポジトリに移動して`npm i`を実行する（この先の手順でもterminalでコマンドを実行する操作がいくつか出てきますが、全てソースコードのリポジトリで実行してください）
4. [LINE Developers](https://developers.line.biz/ja/)に移動して先ほど作成したチャネルを開き、以下の設定をする
   1. "Messaging API設定"→"LINE公式アカウント機能"から"グループ・複数人チャットへの参加を許可する"を有効化、"応答メッセージ"を無効化、"あいさつメッセージ"を無効化する
   2. チャネルアクセストークン（長期）を発行し、コピーしてどこかにメモしておく
   3. "チャネル基本設定"→"基本情報"からチャネルシークレットを発行し、コピーしてどこかにメモしておく
5. ソースコードがあるリポジトリに`.env`というファイルを作成して、以下のコードを記述する
```.env
channelSecret=先ほどコピーしたチャネルシークレット
channelAccessToken=先ほどコピーしたチャネルアクセストークン
```
6.[ngrok](https://ngrok.com/)にログインする
7. 左側のメニューにある`Your Authtoken`を選択する
![スクリーンショット 2022-05-19 11.19.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/af12e2da-5ba6-3dce-551e-ca878469b12b.png)
8. Tokenが表示されるのでコピーする。
![スクリーンショット 2022-05-19 11.23.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/038a7553-a3d1-0ddc-027a-57baaed72d71.png)
9. terminalで以下のコマンドを入力する
```terminal
npx ngrok authtoken 先ほどコピーしたngrokのtoken
```

以上で初回の準備は完了です！
上記の手順はサーバ初回起動時のみ必要となるため、2回目以降サーバを起動したい場合は以下の[サーバ起動](#サーバ起動)の手順を行えば大丈夫です。

### サーバ起動

1. `npm start`を実行する（これでNode.jsのサーバが3000番ポートで起動されます）
2. terminalをもう1つ開いて、`npx ngrok http 3000`を実行する（これでローカルPCの3000番ポートが外部に公開されます）
3. `Forwarding`という項目が2つありそれぞれURLが記述されているので、`https`から始まる方をコピーする
4. [LINE Developers](https://developers.line.biz/ja/)に移動して先ほど作成したチャネルを開き、以下の設定をする
   1. "Messaging API設定"→"Webhook URL"に、先ほどコピーしたURL<!-- の`Production` -->の後ろに`/webhook`を追加したものを貼り付ける
   2. "Webhookの利用"をオンにする（2回目以降この手順は必要ありません）
5. 完成！！！

## 動かしてみよう

<!-- 1. vercelのログ出力画面にアクセスする
   1. 先ほどコピーしたURLの`Inspect`の方にアクセスする
   2. `Functions`タブを開く（アクセスがあるとログが自動更新されます） -->
1. [LINE Developers](https://developers.line.biz/ja/)に移動して先ほど作成したチャネルを開き、"Messaging API設定"→"ボット情報"→"QRコード"に掲載されているQRコードを読み取って友達追加する
2. 挨拶メッセージが返ってきたら設定成功です！

※サーバのログは先ほど`npm start`を実行したterminalに表示されるので、メッセージを送ったらどんなログが表示されるか確認してみましょう

<!-- ## Vercelにデプロイしてみよう

ngrokはローカルPC上に立っているサーバを外部公開できる形にしているため、ローカルPCをスリープしたりシャットダウンするとアクセスできなくなります。
また、ngrokで発行したURLは2時間経つと無効になります（ngrokのアカウントを作ってログインすると有効期限がなくなるので、興味のある方は試してみてください）。
開発中は便利ですが実用性に欠けるため、Vercelというサービスを使ってリモートのサーバでBotを実行できるようにしてみましょう。

1. `npx vercel login`を実行する
   - メールアドレスなどを聞かれるので、登録した情報を入力してvercelにログインする
2. `npx vercel link`を実行して新しいプロジェクトを作成する
   1. 対話型で色々聞かれるので、適当なプロジェクト名などを入力していく（セットアップディレクトリを聞かれるので、カレントディレクトリが`aizuhack-bot`になっている場合はy。すでにある環境を使うか、設定を上書きするかを聞かれるが、どちらも`n`を選択する。）
   2. ![スクリーンショット 2021-06-23 15.53.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/65a9a2f1-38fa-37ca-8c0c-e037bf5f8d96.png)
3. 上記の手順でコピーしたアクセストークンとチャネルシークレットを、以下の手順でvercelの環境変数に登録する
   1. `npx vercel env add`を実行する
   2. `channelAccessToken`と入力する
   3. 先ほどコピーしたアクセストークンを入れる
   4. `Production`, `Preview`, `Deployment`すべてにチェックをいれる
   5. `npx vercel env add`を実行する
   6. `channelSecret`と入力する
   7. 先ほどコピーしたチャネルシークレットを入れる
   8. `Production`, `Preview`, `Deployment`すべてにチェックをいれる
4. `npx vercel deploy --prod`を実行する
   1. `🔍  Inspect: https://vercel.com/XXXXXXXXXX/XXXXXXXXXX/XXXXXXXXXX [4s]`といったURLが吐き出されるのでコピーしておく
   2. `✅  Production: https://XXXXXXXXXXXXXX.vercel.app [33s]`といったURLが吐き出されるので、これをコピーしておく
5. [LINE Developers](https://developers.line.biz/ja/)に移動して先ほど作成したチャネルを開き、以下の設定をする
   1. "Messaging API設定"→"Webhook URL"に、先ほどコピーした`Production`のURLの後ろに`/webhook`を追加したもの(e.g. `https://XXXXXXXXXXXXXX.vercel.app/webhook`)を貼り付ける

以上の手順を行ったら、botに`こんにちは`と送ってみましょう。`Hello, world`と返ってきたら成功です！ -->

## コード解説

### eventの種類

LINE Messaging APIのWebhookには様々なイベントがあります。
今回のサンプルコードで使用しているイベントを以下で簡単に解説します。

※途中で挿入しているイベント例は公式リファレンスから引用したものになります

#### 共通プロパティ

すべてのイベントに共通するプロパティについて解説します。イベントは以下のような形になっています。

```json
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "0f3779fba3b349968c5d07db31eab56f",
      "type": "message",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "user",
        "userId": "U4af4980629..."
      },
      ・・・
    }
  ]
}
```

- destination
  - botのuserId
  - userIdとはLINEのアカウントを識別するIDで、ユーザー✖️プロバイダで一意になっています
    - つまり、プロバイダが変わると同じユーザーでもuserIdが変わります
- events
  - Webhookイベントが入っています
    - replyToken
      - イベントへ応答する際に使用するトークンです
      - これが含まれているイベントには返信できます
    - type
      - イベントのタイプです
      - イベントの種類については[eventの種類](#eventの種類)で解説しています
    - mode
      - チャネルの状態です
      - botがアクティブかどうかの情報が入っています
    - timestamp
      - イベントが発生した時刻のタイムスタンプです
    - source
      - イベントの送信元情報が入っています
      - `type`にどこから送られてきたかが入っています（`user`や`group`など）
      - 送信元のuserIdやgroupIdも含まれています

#### メッセージイベント

- メッセージが送られてきた時に発生するイベントです
- メッセージには以下の種類があります
  - テキスト
  - イメージ
  - ビデオ
  - オーディオ
  - ファイル
  - 位置情報
  - スタンプ

それぞれのメッセージのjsonは[リファレンス](https://developers.line.biz/ja/reference/messaging-api/#common-properties)で確認できます。

#### 送信取消イベント

メッセージが送信取り消しされた時に発生するイベントです。

中身は以下のような形になっています。

```json
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "type": "unsend",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "group",
        "groupId": "Ca56f94637c...",
        "userId": "U4af4980629..."
      },
      "unsend": {
        "messageId": "325708"
      }
    }
  ]
}
```

- unsend.messageIdに送信取り消しされたmessageIdが格納されています。
- replyTokenが含まれていないため、このイベントに対して返信することはできません

#### フォローイベント

Botのアカウントが友達追加されるかブロック解除された時に飛んでくるイベントです。

イベントの中身は以下のような形になっています。

```json
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
      "type": "follow",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "user",
        "userId": "U4af4980629..."
      }
    }
  ]
}
```

- このイベントにはreplyTokenが含まれているため返信できます

#### フォロー解除イベント

Botがブロックされた時に飛んでくるイベントです

```json
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "type": "unfollow",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "user",
        "userId": "U4af4980629..."
      }
    }
  ]
}
```

- このイベントにはリプライトークンがないため返信はできません

#### 参加イベント

- botがグループまたはトークルームへ参加した時に飛んでくるイベントです

```json
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
      "type": "join",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "group",
        "groupId": "C4af4980629..."
      }
    }
  ]
}
```

- このイベントにはreplyTokenが含まれているため返信できます

#### 退出イベント

- botがトークルームやグループから退出したさいにとんでくるイベントです

```json
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "type": "leave",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "group",
        "groupId": "C4af4980629..."
      }
    }
  ]
}
```

- このイベントにはreplyTokenが含まれていないため返信はできません

#### メンバー参加イベント

Botが参加しているグループにメンバーが参加した時にとんでくるイベントです

```json
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "0f3779fba3b349968c5d07db31eabf65",
      "type": "memberJoined",
      "mode": "active",
      "timestamp": 1462629479859,
      "source": {
        "type": "group",
        "groupId": "C4af4980629..."
      },
      "joined": {
        "members": [
          {
            "type": "user",
            "userId": "U4af4980629..."
          },
          {
            "type": "user",
            "userId": "U91eeaf62d9..."
          }
        ]
      }
    }
  ]
}
```

- 参加したユーザーの情報が配列形式で`joined.members`に格納されています
- このイベントにはreplyTokenが含まれているため返信できます

#### メンバー退出イベント

- Botが参加しているトークルームやグループからメンバーが退出した時にとんでくるイベントです

```json
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "type": "memberLeft",
      "mode": "active",
      "timestamp": 1462629479960,
      "source": {
        "type": "group",
        "groupId": "C4af4980629..."
      },
      "left": {
        "members": [
          {
            "type": "user",
            "userId": "U4af4980629..."
          },
          {
            "type": "user",
            "userId": "U91eeaf62d9..."
          }
        ]
      }
    }
  ]
}
```

- `left.members`に配列形式で退出したメンバーのリストが格納されています
- このイベントにはreplyTokenが含まれていないため返信はできません

#### ポストバックイベント

- ポストバックとはトーク上に表示されない、「見えないメッセージ」のようなものです
- トーク上には何も表示されませんが、サーバにデータは飛んできます

```json
{
  "destination": "xxxxxxxxxx",
  "events": [
    {
      "replyToken": "b60d432864f44d079f6d8efe86cf404b",
      "type": "postback",
      "mode": "active",
      "source": {
        "userId": "U91eeaf62d...",
        "type": "user"
      },
      "timestamp": 1513669370317,
      "postback": {
        "data": "storeId=12345",
        "params": {
          "datetime": "2017-12-25T01:00"
        }
      }
    }
  ]
}
```

- `postback.data`にdataが格納されています
- 日時選択アクションの場合は`postback.params`に日時データが含まれています

### メッセージオブジェクトについて

LINE Messaging APIで返信できるメッセージには以下の種類があります

#### クイックリプライ

クイックリプライは以下の画像のようなメッセージです。
次のメッセージがトークに送信されると選択肢が消えます。

![IMG_1978.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/fe0b7fd5-b960-5571-88f1-f6b3535fb48c.png)

#### テキストメッセージ

![IMG_1979.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/6c88eed1-8d1f-d2db-76b4-627fda7e2fed.png)

#### スタンプメッセージ

![IMG_1980.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/f793a732-b0fa-ec40-7a00-48a66a819ad0.png)

#### 画像メッセージ

![IMG_1981.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/69c38332-410f-6c1a-439d-d956a1e16b7c.png)

#### 動画メッセージ

![IMG_1982.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/c5abda6c-2702-6346-3351-274df7b11331.png)

#### 音声メッセージ

![IMG_1983.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/4ada3ce2-7aa6-e13d-1f3a-4c0e1c2dcec1.png)

#### 位置情報メッセージ

![IMG_75048DDFCE46-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/1b84b1f7-ecfd-b5d8-2003-3fce204abb8d.jpeg)

#### イメージマップメッセージ

1つの画像の中に複数のタップ領域を設定できるタイプのメッセージです

#### ボタンテンプレート

画像、タイトル、テキスト、ボタンで構成されたメッセージです

![IMG_1985.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/b96c84f4-2010-88e2-0894-f64650b5e26f.png)

#### 確認テンプレート

テキストに加えて、2つのボタンが平行に表示されます

![IMG_1986.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/085cb3fe-280f-b9db-e462-7bb8b49d5de8.png)

#### カルーセルテンプレート

複数のカラムを横にスクロールする形で表示できます。

![IMG_1987.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/fc41a566-49cb-417a-9446-ad7007d867f1.png)

#### 画像カルーセルテンプレート

カルーセルの全面画像版です

![IMG_1988.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/04abcc2b-1e73-5534-eff0-ad5c94e80fa3.png)

#### Flex Message

CSS Flexible Boxの記法をベースに作れるメッセージで、とても自由度が高いです。
Flex Messageに関しては第二回勉強会で解説します。

![IMG_E1A9A475D122-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/43049ed5-8c69-7b33-9b3c-2d2a18f677a5.jpeg)

### ディレクトリ構成

本サンプルコードのディレクトリ構成は以下のようになっています

```directory
- /
  - api/ 
    - server.js
  - event/
    - follow.js
    - join.js
    - leave.js
    - memberJoined.js
    - memberLeft.js
    - postback.js
    - unfollow.js
    - unsend.js
    - message.js
    - message
      - audio.js
      - file.js
      - image.js
      - location.js
      - sticker.js
      - text.js
      - video.js

  - bot.js
  - config.js
  - vercel.json
```

### 実行の流れ

LINEBotで何かイベントが発生した際、今回のサンプルコードでは以下の流れで処理をします。

- たとえば「こんにちは」というメッセージを送った場合

ユーザーがメッセージを送信する → LINEのサーバに送られる → LINEのサーバからngrokの`/webhook`にリクエストが飛んでくる → 自分のPCにたてたNode.jsサーバにリクエストが飛んでくる → server.jsが呼び出される → server.jsがbot.jsを呼び出す → bot.jsがmessage.jsを呼び出す → message.jsがtext.jsを呼び出す → text.jsが「Hello, World」というメッセージをmessage.jsに返す → message.jsが返信するメッセージをbot.jsに返す → bot.js返信するメッセージをLINEのサーバに送る → LINEのサーバからユーザーにメッセージが送られる

### 各ファイルのコード解説

#### /api/server.js

サーバを起動するコードが書いてあるファイルです。`/`にGETのアクセスがきたら`Deploy succeeded`とレスポンスし、`/webhook`にPOSTのアクセスがきたら/bot.jsのindexを呼び出してその実行結果をレスポンスするというコードになっています。

#### /bot.js

LINEから送られてきたリクエストを処理するコードが書いてあるファイルです。`/event`にそれぞれのイベントを処理するファイルが格納されているため、イベントに合わせてそれぞれのファイルを呼び出す処理が書かれています。

#### /event/follow.js

Botのアカウントが友達追加された時に呼び出されるファイルです。
`友達追加ありがとうございます！`と返信する処理が書いてあります。

#### /event/join.js

Botがトークルームやグループへ招待された時に呼び出されるファイルです。
`招待ありがと！！`と返信する処理が書いてあります。

#### /event/leave.js

Botがトークルームやグループから退出した時に呼び出されるファイルです。
`botがグループから退出しました`とログに出力する処理が書いてあります。

#### /event/memberJoined.js

Botが入っているグループやトークルームにユーザーが参加した時に呼び出されるファイルです。
`ユーザーが参加しました！ 参加したユーザー: userId`と返信される処理が書かれています。

#### /event/memberLeft.js

Botが入っているグループやトークルームからユーザーが退出した時に呼び出されるファイルです。
`ユーザーが退出しました... 退出したユーザー: userId`と返信される処理が書かれています。

#### /event/message.js

メッセージが送られてきた時に呼び出されるファイルです。
テキストが送られてきた場合は`/event/message/text.js`, イメージは`/event/message/image.js`, ビデオは`/event/message/video.js`, オーディオは`/event/message/audio.js`, ファイルは`/event/message/file.js`, 位置情報は`/event/message/location.js`, スタンプは`/event/message/sticker.js`がそれぞれ呼び出されます。

`/event/message/text.js`では送られてきたメッセージで条件分岐して返信するメッセージを決める処理が書かれています。`/event/message/image.js`, `/event/message/video.js`,`/event/message/audio.js`, `/event/message/file.js`では`/download`ディレクトリにファイルを保存したのち、メッセージを返信する処理が書かれています。
`/event/message/location.js`では受け取った住所を返信する処理、`/event/message/sticker.js`には受け取ったスタンプのIDを返す処理が書かれています（特定のスタンプを受け取った時のみあるスタンプを返信する処理も書かれています）。

返信に対応しているメッセージは以下の通りです

以下のメッセージを送信して何が返ってくるか試してみましょう！

- テキスト
  - こんにちは
  - 複数メッセージ
  - クイックリプライ
  - スタンプメッセージ
  - 画像メッセージ
  - 位置情報メッセージ
  - イメージマップメッセージ
  - ボタンテンプレート
  - 確認テンプレート
  - カルーセルテンプレート
  - 画像カルーセルテンプレート
  - Flex Message
  - プロフィール
  - ここはどこ
    - 個チャ、グループ、トークルームで返信されるメッセージが変わります
- イメージ
- ビデオ
- オーディオ
- ファイル
- 位置情報
- スタンプ

#### /event/postback.js

ポストバックイベントが飛んできた時に呼び出されるイベントです。

- ポストバックイベントとは

ポストバックイベントとは、表に表示されないメッセージのようなものです。トーク画面には表示されませんが、サーバへデータが飛んできます。

テンプレートメッセージなどでポストバックアクションが実装されているボタンを押すとポストバックイベントが飛んできます。

#### /event/unfollow.js

botがunfollow（ブロック）された時に飛んでくるイベントです。
`unfollowされました...\nuserId: ${userId}`とログに表示される処理が書かれています。

#### /event/unsend.js

メッセージが送信取り消しされた時に飛んでくるイベントです。
`メッセージが取り消されました！\n取り消されたmessageId: ${messageId}`と返信される処理が書かれています

#### config.js

アクセストークンやチャネルシークレットなどのコンフィグ情報を読むこむ処理が書かれています。

<!-- #### vercel.json

vercelに関するコンフィグが書かれているファイルです -->

### アクションオブジェクトについて

テンプレートメッセージのボタンなどを押したときに実行される操作を、アクションオブジェクトというものを用いて記述することができます。

詳しくは[こちら](https://developers.line.biz/ja/reference/messaging-api/#action-objects)のリファレンスに記載されています。

## ソースコードを更新する方法

nodemonを使ってホットリロードできるようになっているので、変更を加えたらファイルを保存するだけでサーバが勝手に再起動されて自動で適用されます。

PCをスリープ/シャットダウンしたりVSCodeを閉じるとNode.jsのサーバ、ngrokのセッションが終了してしまうため、その場合は[サーバ起動](#サーバ起動)の手順を確認しながらサーバ起動、ngrokの実行、WebhookURLの更新を行ってください。

## 演習課題1

「こんにちは」と送信したときに返ってくるメッセージを「こんにちは世界」に変えてみましょう。

## 演習課題2

「おはよう」と送信したら「Good Morning!」と返信するコードを追加してみましょう。

## 演習課題3

自分のQ2の時間割を確認するbotを作ってみましょう。要件は以下のとおりです。

- 「時間割」と送信すると、曜日を選択するボタンが出てくる（クイックリプライを使用すると良さげ）
- ボタンを押すと、その曜日の時間割が送られてくる

## 演習課題4(宿題)

勉強会の評価アンケートをLINEBotで実装してみましょう（アンケート形式だけを実装すれば良くて、アンケート結果を保存する必要はありません）。
選択肢の実装はボタンテンプレートやクイックリプライを使うと良いかもしれません。
自由記述の実装方法はいくつか考えられますが、思いつかなかったら選択肢の項目を実装するだけでも大丈夫です。

## 演習課題5（宿題）

今回の勉強会で、LINEBotにできることはだいたいわかったのではないでしょうか。次回までに自分が作ってみたいLINEBotをいくつか考えてみましょう（次回ちょこっと発表してもらうかもです）。

## おわりに

皆さんお疲れ様でした。このソースコードを全て理解する必要はないので、まずは「どこをいじったらどう動くのか」を知るためにたくさんコードをいじくりまわしてみましょう。

第2回はLINE Bot Designerの使い方、Flex Messageの作り方、リッチメニューの作り方、PUSHメッセージについて解説する予定です。

第二回はこちら: [AizuHack LINEBot勉強会 Vol.2](https://qiita.com/shinbunbun_/items/4034e9c2c7553ed3107e)