[無料][2024年版] LINE Messaging API v3 + Python(Flask) でボットを作る [その5 - tips 編]

今回は開発時におけるお役立ち情報について紹介していこうと思います。特にローカルでの開発についてです。

## Render のスリープ対策

Render の無料枠は15分間アクセスがないと自動でスリープしてしまい、スリープ中のアクセス時の再立ち上げにはかなり時間がかかる仕様です。再立ち上げの際に送ったメッセージはおそらく処理されずに、返信なしになってしまうでしょう。これに関しての対策は他の記事でもたくさん解説されているので詳細には書きませんが、私は [UptimeRobot](https://uptimerobot.com/) を使用しています。

これは定期的に HEADリクエスト（GETリクエスト同様だが、コンテンツまでは取得しない）を送って、サーバーがダウンしていないかをモニターするサービスです。このように、ダウンしている期間は赤で表示されます。

![Screenshot 2024-01-07 at 11.45.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727634/765dafa7-301e-5daf-6613-c6195dd070ca.png)

これを使い、5~10分ごとにリクエストを送ることでスリープを回避できます。前回までのコードで起動確認用のウェブサイト（Hello Worldが表示されるだけ）も作ってありましたから、Render で発行される `https://xxxxxx.onrender.com` というURLをそのまま監視対象にしてしまえば良いです。

## ローカル環境でのテスト準備

実際のボット開発においてはエラーとデバッグの繰り返しになりますから、コードを少し修正するたびに `git push` してデプロイして...などはやっていると非常に面倒です。まずは自分のローカルPC上でテストをし、問題なければプッシュ＆デプロイする方が圧倒的に楽です。

ローカル環境でのテストのために準備するものが以下の2つです。

- テスト用の LINE Developers チャネル
- [**ngrok**](https://ngrok.com/download)

LINE Developers チャネルはいくつも作れます。私もテスト用チャネルは色々なボットで使い回ししています。

チャンネルトークンとシークレットトークンを発行したら、`test.env` というファイルを作成し、`.env` ファイル同様に書き込んで保存しておきます。

~~~python:test.env
CHANNEL_ACCESS_TOKEN=aw...
CHANNEL_SECRET=b6...
~~~

[**ngrok**](https://ngrok.com/download) は、ローカルの Webサーバーを外部に公開する、トンネリングツールと言われるものです。LINE Messaging API の Webhook送信先をこの ngrok で発行されたURLに設定することで、自動的にローカルPCの方に送られてくるということですね。

ngrok の登録方法、設定方法などは他記事を参考にして下さい。

https://labo.kon-ruri.co.jp/ngrok/

設定が終わってから、ターミナルで `$ ngrok http 8000` と実行してみると、このような感じで立ち上がります。一旦 `Ctrl + C` で終了します。

![Screenshot 2024-01-07 at 12.32.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727634/f98df355-fa83-71cf-9703-618cf21e2698.png)

## ローカル環境での立ち上げ

では実際にローカル環境でサーバーを立ち上げ、そこでボットのテストをします。順序としては

1. `app.py` 内で、読み込む環境変数ファイルを切り替え
2. 仮想環境内でサーバー立ち上げ
3. ngrok 立ち上げ
4. LINE Developers のテスト用チャネルの Webhook URL の変更  

となります。

#### 1. 環境変数ファイルの切り替え

`app.py` 内で環境変数を読み込む際に、`load_dotenv()` という関数を使いましたが、これはファイルパスを指定できます（デフォルトだと `.env`）。なので、これを先ほど作成した `test.env` に替えて、テスト用ボットのトークンを読み込むようにします。

~~~python:app.py
from dotenv import load_dotenv
load_dotenv('test.env', override=True)
~~~

コード内にテスト用のトークンを直接書き込んで変数を上書きするという方法もありますが（というか、私も最初はそうやってました）、それだと間違って消し忘れたまま GitHub にアップして公開してしまう可能性があったりします。別ファイルにした上で `.gitignore` での管理をしっかりしておけば、間違ってトークンを公開してしまう可能性はありませんし、一々コピペする手間も省けます。ただ、本番環境で`load_dotenv('test.env')` の部分を消し忘れると起動しなくなりますが。

#### 2. 仮想環境内でサーバー立ち上げ

Render での起動コマンド同様に、仮想環境内で `$ gunicorn app:app` で立ち上げられますが、ここでは Flask 自体を使って

~~~bash
(venv) linebot $ python app.py
~~~

としましょう。`app.py` の最後に `app.run(host="0.0.0.0", port=8000, debug=True)` としてあれば、`gunicorn` 同様に8000番ポートで立ち上がり、さらにファイルを上書き保存すればその度に自動でリスタートする（デバッグモード）ので、コードの修正が非常にやりやすくなります。

![Screenshot 2024-01-07 at 16.41.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727634/bf16c126-3185-dd39-57e8-321fa911f94a.png)

#### 3. ngrok 立ち上げ

上述のように、ローカルの8000番ポートでサーバーを立ち上げた状態で

~~~bash
$ ngrok http 8000
~~~

を実行すると、ngrok が立ち上がります。

![Screenshot 2024-01-07 at 12.32.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727634/f98df355-fa83-71cf-9703-618cf21e2698.png)

この `Forwarding` の `https://...app` の部分が、トンネル用のURLになります。試しにこれをコピーしてブラウザのURLバーに貼り付けると、このような確認画面が出ます。

![Screenshot 2024-01-07 at 16.35.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727634/e490505f-7da3-c502-0a0d-94d311df11a3.png)

ここで Visit Site をクリックすると、起動確認用の Hello World! ページに飛べるはずです。

(2)(3) 共に、終了時はターミナルで `Ctrl + C` です。

#### 4.  LINE Developers のテスト用チャネルの Webhook URL の変更 

最後に、テスト用チャネルの設定画面にいき、Messaging API の項目から Webhook URL を ngrok のものにします。

![Screenshot 2024-01-07 at 16.37.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727634/a59767e4-78b8-db5c-1603-2ffdcd289ae5.png)


ngrok は毎回URLが変わるので、立ち上げ直す度にこの部分も変更する必要があります。検証ボタンを押して「成功」と出たら、あとはテスト用のボットを使って機能チェックをします。もしエラーが生じた場合は、そのままターミナルにエラーメッセージが出力されるのでデバッグも楽です。

## `.gitignore` の設定

https://qiita.com/anqooqie/items/110957797b3d5280c44f

GitHub にアップする上で無視するファイルを記載しておく `.gitignore` ですが、私は以下のようにしています

~~~:.gitignore
**.DS_Store
**__pycache__
*.env
*.ipynb
venv
~~~

`.DS_Store` というのは、MacOS 専用の隠しファイルです。Finder でのファイル管理のためのものらしいです。`git commit` するとこれが勝手に付いてきてしまうので、無視します。`**` というワイルドカードを入れることで、サブディレクトリ以下の全てのファイルも同様に無視できます。

`__pycache__` は python を実行した時にもれなく付いてくるキャッシュファイルです。jupyter notebook の場合、`.ipynb_checkpoints` も生成されたりします。これらもデプロイには不要なので、無視してしまいましょう。

`*.env` は必須です。本番環境用の `.env` ファイルと、テスト用の `test.env` の2つを作ったため、そのどちらもアップロードしないようにしています。

notebook を使って関数などの動作テストを行うこともよくあると思います。その場合に、その notebook ファイルを無視するのが `*.ipynb` です。`test` というディレクトリを作り、その中に notebook を作った上で、そのディレクトリ全体を無視するという方式も良いと思います。

`venv` は仮想環境です。これは当然アップロード不要です。

## API に直接リクエスト - Postman

Webhook の処理をコーディングする以外に、送られてくるメッセージがどのようになるのかチェックしたいことがしばしばあります。前回のクイックリプライに加え、今後使うテンプレートメッセージや Flex メッセージなどではなおさらです。また、リッチメニューの細かい設定をする時などは、わざわざ Python の SDK を使う必要性はそこまでありません。そこで役に立つのが **Postman** というツールです。

これは API に送るJSONリクエストを保存しておき、ボタン一つで実行できる優れものです。↓に載っている例のように、いちいちターミナルで `$ curl -v -X POST ...` などと打ち込む必要はありません。

https://developers.line.biz/ja/docs/messaging-api/sending-messages/#send-messages-at-any-time

細かい使い方はこちらなどを参照して下さい。

https://apidog.com/jp/blog/postman-user-manual/

`linebot.v3.messaging` の中にある様々なクラスは `.to_json()` というメソッドを完備しており、JSON出力できるようになっています。それを "messages" プロパティにそのまま貼り付けて送信する、という方法をよく使います。後の回でも紹介しますが、以下は Flex Message をプッシュ送信（任意のタイミングでメッセージ送信）するときの例です。

![Screenshot 2024-01-07 at 17.36.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/727634/012cc0da-e61c-fa75-f01d-c2d126f27b7d.png)

- 上部のAPIエンドポイントは `https://api.line.me/v2/bot/message/push`
- `Auth` の項目は `Bearer Token` タイプを選び、チャンネルアクセストークンを入れる
- `Headers` は Key を `Content-Type`、Value を `application/json`
- `Body` は `{"to": "<自分のUSERID>", "messages": [メッセージオブジェクトから .to_json() で出力したJSON] }`

とすれば送信可能です。

ということで tips 編は終了です。次回からは、機能をさらに追加していくと共に、複雑になったコードをモジュール化して整理していきます。

## 目次 : [無料][2024年版] LINE Messaging API v3 + Python(Flask) でボットを作る

[GitHub レポジトリ](https://github.com/nozomiyamada/linebot/tree/main)
`older_version` 内に、各回時点での `app.py` と `requirements.txt` があります。

- [その0 - v3 での変更点](https://qiita.com/nozomiyamada/items/dff5f240e8c936d731fd)
- [その1 - 準備編](https://qiita.com/nozomiyamada/items/f6c6816e02359e08a74e)
- [その2 - テストアプリ編](https://qiita.com/nozomiyamada/items/87389aacb151b8418501)
- [その3 - 情報検索理論(前編)](https://qiita.com/nozomiyamada/items/d1bcedcc885c43794ff7)
- [その4 - 情報検索理論(後編)](https://qiita.com/nozomiyamada/items/6b0b30ebc36eeddc73d2)
- その5 - tips 編
- [その6 - モジュール化編](https://qiita.com/nozomiyamada/items/b80eaf5aef0c294c4acf)
- [その7 - クラス化編](https://qiita.com/nozomiyamada/items/c8315c8a0f0f7d19129b)
- [その8 - Flex Message 編](https://qiita.com/nozomiyamada/items/1be9ae292b01fb35273e)
- [その9 - ポストバック編](https://qiita.com/nozomiyamada/items/8a236a2d38f33827b4ce)
- [その10 - リッチメニュー & LIFF 編](https://qiita.com/nozomiyamada/items/ffbeeafbadfa6e98c711)