LINE Messaging APIのsdkをPython(2.7.9)+GoogleAppEngineで利用した際のいろいろ備忘録

#はじめに

[LINE Messaging API](https://business.line.me/ja/) を使ったBotを Python + [Google App Engine](https://cloud.google.com/appengine/) 環境で作ってみたときに、色々知らなかったことがあったので備忘録としてここに書き記しておきたいと思います。
#環境の構築時の注意点

- **GoogleAppEngine** などと検索すると色々情報は出てきますので、インストールや設定の詳しいことはそちらにおまかせしたいと思います。

- 今回は**Python**の**Standard environment**を利用しました。Pythonには**Flexible environment**の環境も用意されていて、スタンダード環境よりも環境は良いですが無料枠がないらしいです。

---

- 今回利用したPythonは*2.7.9*ですがPython3版の**Anaconda**によるバージョン管理下にあります。
 - そのためGoogle Cloud SDK をコマンドで素のまま使うことはできず、一度Anacondaでpy27環境を作成して、```activate py27```などしてからコマンドを打ち込む必要がありました。
 - ちなみにAnacondaで別のバージョンをactivateして利用しているときはコマンドのとこに**(py27)**と表示されます。

---

- デプロイは**Google Cloud SDK**を使ってコマンドでやります。詳しくはこれもGAEのドキュメントを読めばわかります。
 - 初期起動時は```gcloud auth login```でアカウントの紐付け、```gcloud init``` して画面に従って設定をして、```gcloud app deploy [プロジェクトのyamlファイル]``` もしくはプロジェクトのルートディレクトリで ```gcloud app deploy ```をすればOK。
 - ```gcloud app deploy --version 2``` などデプロイするときにバージョンを管理することも可能。

#デプロイ時の注意点

- スタンダード環境ではPythonのライブラリがファイルに「これを使います！」と書いただけでは使えず、自分でメインのファイルと一緒にデプロイする必要があります。

---
- ```pip install [モジュール] -t [インストール場所]```などを使って依存関係などを解決した形でインストールしたほうが良いです。(**-t** = **--target**で通常のモジュールの場所とは違うところにインストールするときに使います。)
 - ちなみにコマンドで```pip install -help```などと入力すると**pip**の**install**に於ける**help**が表示されます。最初からこれがわかればあんなに苦労しなかったのに...

---

- また、ただ単にライブラリを一緒にデプロイしただけでも十分ではなく、色々と設定が必要です。
公式DOCによれば**appengine_config.py**なるものを一緒にデプロイすることでモジュールが入った**lib**ディレクトリを認識可能にすることができます。
他のディレクトリを認識させる場合は下のコードで*lib*を*[任意の名前]*に変えれば大丈夫だと思います。

```python:appengine_config.py
# [START vendor]
import os
from google.appengine.ext import vendor

# Add any libraries installed in the "lib" folder.
vendor.add(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib'))
# [END vendor]

```

- またどう必要かはよくわかりませんでしたが**requirements.txt**も一緒にしておいたほうが良さそうです。```pip freeze```した結果を貼り付ければとりあえずOKっぽいです。

以上の設定でようやくコード側で

```python:コード
import flask
```
とかができるようになります。

#LINE Messaging API利用の注意点

- **LINE Messaging API**にはpython用のライブラリがあり、実は今回はその利用というのも目的の一つでした。[line-bot-sdk-python on GitHub](https://github.com/line/line-bot-sdk-python) (pipでインストールできます。)

- またここでの注意点は、**line-bot-sdk-python**にはrequestsというモジュールが外部との通信のため要求されていますが**GAEではrequestsは使えない。**ということです。(GAEでget,postなどをするためにはURLFetchというGoogleのモジュールが必要)

色々と調べた結果URLFetchとrequestsの橋渡しをするモジュールがあったのでインストールし、以下のようにline-bot-sdk-pythonに追加・変更しました。

```python:/lib/linebot/api.py
#※/libはモジュールをインストールしたディレクトリです。

# [START imports]
import requests
import requests_toolbelt.adapters.appengine

# Use the App Engine Requests adapter. This makes sure that Requests uses
# URLFetch.
requests_toolbelt.adapters.appengine.monkeypatch()
# [END imports]
```
これでline-bot-sdk-pythonに大きな変更を加えずにGAEで利用する事ができます。
このライブラリがあると、自分でLINE返信用のオブジェクトを作る必要がなくなります。
**LINE Messaging API** の詳しい仕様はこちら：[Line API Reference](https://devdocs.line.me/ja/)

##line-bot-sdk-pythonの解説を少し


```python:HTTPSの受付側コード
    jsonObject = request.json
    line_request = jsonObject['events'][0]  # requestが送られてきた内容
```
ここではline_requestでLINEから来たメッセージの内容を見ることができます。
メッセージ処理をするコードの頭にこのように書いておきます。

```python:BOTのメインのコード
    line_bot_api = LineBotApi(your_channel_access_token)
    parser = WebhookParser(your_channel_secret))
```

あとはかんたんです。(ここでのメッセージオブジェクトとはLINE側で言う*Send message object*のことです。)

```python:BOTのメインのコード
        line_bot_api.reply_message(
            replyToken,
            TextSendMessage(text=event.message.text)
        )

```

- ```line_bot_api.reply_message(replyToken, メッセージオブジェクト)``` で返信

---

### メッセージオブジェクトの作り方

- ```オブジェクト(テキスト) = TextSendMessage(text="テキスト")```
- ```オブジェクト(写真) = ImageSendMessage(original_content_url="元画像のURL", preview_image_url="サムネイルのURL")```
- ```オブジェクト(動画) = VideoSendMessage(original_content_url="元動画のURL", preview_image_url="サムネイルのURL")```
- ```オブジェクト(動画) = AudioSendMessage(original_content_url="元音声のURL", duration="長さ(1分以内)")```
- ```オブジェクト(動画) = LocationSendMessage(title="タイトル", address="住所", latitude="緯度", longitude="経度")```
- ```オブジェクト(動画) = StickerSendMessage(package_id="パッケージID", sticker_id="ステッカーID")```