はじめに
つい最近、LINE の Messenger API の v3 なるものを試す機会があり(この記事)、しばらくいじっているうちにやっと使い方がわかってきたのでここにメモしておこうと思います。
わざわざこうやって記事にまとめようと思った理由は、もちろん自分用の備忘録が一番ですが、他にも
- Line は日本、タイ、台湾などでしか使われていないガラパゴスツールなので、Stack Overflow に情報がない
- Qiita の情報も、v3 以前のものが多い
- そもそもPython で開発している人も多くない
- 本家
line-bot-sdk
の GitHub の説明が少なすぎる
などの理由から、せっかくなので共有しておこうと思ったからです。あくまで個人開発のレベルで、専門的なことはパッパラパーなのですが、こんな素人の私の記事でも多少は役に立つ内容にしようと思います。
ちなみにどうしても Python + Flask を使いたい方向けの解説です。最近はGAS(Google Apps Script)を使って開発する方も多く、そちらの方がGCPでデプロイもできるので楽です。私が Python を使う理由は機械学習や自然言語処理系のライブラリを使っているからであり、そういったものを必要としないならばGASの方が簡単にできると思います、記事もたくさん見つかります。
これから何回かに分けて記事を書いていく予定ですが、今回はまず v3 という新しいバージョンがどういうものか、実際に使ってみた内容をまとめてみます。既に Flask + Messeging API を使って開発したことがある方向けの説明なので、「これから Python を使ってボット開発を始めたい!」という方は読み飛ばして、次回以降の記事から読んでいただいても構いません。
v3 について
2023年6月頃に導入された OpenAPI 仕様に沿った新バージョンのSDK(ソフトウェア開発キット)の仕様になります。ただし、APIのエンドポイントは https://api.line.me/v2/bot/ のままで、リクエストの方法も同じです。
こちらにも書かれているように将来的には v3 に統一化するようで、現状でも deprecated warning が出てくるので精神衛生上よろしくありません。なのでこれから開発をする方は、v3 で始めた方が良いかと思います。
v3 での変更点
使っていて気づいた変更点をまとめると、
- 認証用のクラスをインスタンス化
- クラスの再編成
- 返信時は、メッセージタイプに関わらず
ReplyMessageRequest
オブジェクトとして渡す - キーワードのキャメルケース対応化
- Flex Message 用のクラスが導入
というものです。
1. 認証用のクラスをインスタンス化
line-bot-sdk
でメッセージを送信する際は、今まで
app = Flask(__name__)
## APIインスタンス化
line_bot_api = LineBotApi(CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(CHANNEL_SECRET)
## callback認証
@app.route("/callback", methods=['POST'])
def callback():
signature = request.headers['X-Line-Signature']
body = request.get_data(as_text=True)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
abort(400)
return 'OK'
## テキストメッセージ返信
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
### ここでメッセージ処理する
## 返信
line_bot_api.reply_message(event.reply_token, message)
のような形式だったかと思います。これが v3 においては、大幅に変更されています(こちらを参照)。以下は公式のオウム返しサンプルコードです。
app = Flask(__name__)
configuration = Configuration(access_token='YOUR_CHANNEL_ACCESS_TOKEN')
handler = WebhookHandler('YOUR_CHANNEL_SECRET')
@app.route("/callback", methods=['POST'])
def callback():
# get X-Line-Signature header value
signature = request.headers['X-Line-Signature']
# get request body as text
body = request.get_data(as_text=True)
app.logger.info("Request body: " + body)
# handle webhook body
try:
handler.handle(body, signature)
except InvalidSignatureError:
app.logger.info("Invalid signature. Please check your channel access token/channel secret.")
abort(400)
return 'OK'
@handler.add(MessageEvent, message=TextMessageContent)
def handle_message(event):
with ApiClient(configuration) as api_client:
line_bot_api = MessagingApi(api_client)
line_bot_api.reply_message_with_http_info(
ReplyMessageRequest(
reply_token=event.reply_token,
messages=[TextMessage(text=event.message.text)]
)
)
発行した CHANNEL_ACCESS_TOKEN
を渡すのはAPIオブジェクトではなく、Configurtion
という認証用のオブジェクトに代わっています。line_bot_api
のインスタンス化は関数内部(イベントハンドラー内)で行われるようになり、名称も LineBotApi
から MessagingApi
に変更されています。
ちなみに、このAPIのインスタンス化は関数内部ではなく最初にやってしまっても動くことは動きます。つまり、
app = Flask(__name__)
configuration = Configuration(access_token=CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(CHANNEL_SECRET)
## APIインスタンス化
with ApiClient(configuration) as api_client:
line_bot_api = MessagingApi(api_client)
@app.route("/callback", methods=['POST'])
def callback():
...
@handler.add(MessageEvent, message=TextMessageContent)
def handle_message(event):
## メッセージ処理諸々
line_bot_api.reply_message(
ReplyMessageRequest(
replyToken=event.reply_token,
messages=message
)
)
のようにするということです。ただし、認証に関するタイムアウト的な問題なのか、時間が空くとプロトコルエラーが起きたり起きなかったりします(ネットワーク関連の知識が全然なくて申し訳ありません)。なので、素直に関数内でその都度インスタンス化することをオススメします。
また、返信用のメソッドも v3 以前では line_bot_api.reply_message()
だったのが、v3 では line_bot_api.reply_message_with_http_info()
という長ったらしいものに変わっています。
ですが、実は v3 にも .reply_message()
が残されており、ソースコードを見る限りこの内部で .reply_message_with_http_info()
を呼び出している(違いはあるようですが私にはわかりません)ので、私は短い方を使っています。上記のコードもそう修正しています。
2. クラスの再編成
v3 以前で linebot.models
にあった様々なクラスは、送信処理関連の linebot.v3.messaging
と webhook 受信処理の linebot.v3.webhooks
に分離しています。具体的には
linebot.v3.messaging
必ず使うもの
-
Configuration
: 認証用クラス -
MessagingApi
,ApiClient
: APIのインスタンス化
メッセージ送信方法別 (APIドキュメント)
-
ReplyMessageRequest
: webhook に応答して返信する時 -
PushMessageRequest
: 任意のタイミングでプッシュメッセージを送信する時
メッセージタイプ別 (APIドキュメント)
-
TextMessage
,AudioMessage
,TemplateMessage
,FlexMessage
など
アクションタイプ別 (APIドキュメント)
-
PostbackAction
,MessageAction
,URIAction
など
リッチメニュー関連
-
RichMenuArea
,RichMenuSwitchAction
など (APIドキュメント)
のようになっています。従来 webhook のコンテンツ用だった TextMessage
は、v3 では TextMessageContent
となり、逆に TextMessage
はテキストをメッセージオブジェクト化するためのクラスとなっています。
3. 返信時は、メッセージタイプに関わらず ReplyMessageRequest
オブジェクトとして渡す
上述の v3 のサンプルコードの返信部分を確認してみましょう。
@handler.add(MessageEvent, message=TextMessageContent)
def handle_message(event):
with ApiClient(configuration) as api_client:
line_bot_api = MessagingApi(api_client)
line_bot_api.reply_message_with_http_info(
ReplyMessageRequest(
reply_token=event.reply_token,
messages=[TextMessage(text=event.message.text)]
)
)
line_bot_api.reply_message_with_http_info()
の中身が、ReplyMessageRequest
というクラスになっており、messages
というキーワードで各種のタイプのメッセージオブジェクトのリストを受け取るようになっています。
以前は .replay_message()
メソッドに直接 TextSendMessage
や AudioSendMessage
などのクラスを渡していました。v3 ではそれらを一旦 Request オブジェクトにしてから、.replay_message()
に渡すという形式になっています。reply_token
も、この ReplyMessageRequest
に渡します。
4. キーワードのキャメルケース対応化
サンプルコードでは全て以前同様にスネークケースで書かれているのですが、エディタ内ではキャメルケースで表示されたので気づきました。これはエイリアスされていて、どちらで書いても動きます。例えば上述の ReplyMessageRequest
なら、
ReplyMessageRequest(
reply_token=event.reply_token,
messages=[TextMessage(text=event.message.text)]
)
ReplyMessageRequest(
replyToken=event.reply_token,
messages=[TextMessage(text=event.message.text)]
)
の両方が可能です。旧コードをコピーして v3 用に修正する時にはスネークケースのままで問題ありません。
5. Flex Message 用のクラスが導入
これは前回の記事で紹介したんですが、FLex Message を使うためのクラスが充実しています。JSONや辞書を一切書くことなく、オブジェクトの組み合わせで全てが完了します。
もちろん Flex Message Simulator を使ってのプレビュー確認は欠かせませんのでJSON書き出しは使います。また、コーディング量自体にそこまで大差はないですが、各クラスをインスタンス化した際に適切なパラメータを与えないと ValidationError
が出て怒られるので、非常にデバッグがしやすくなりました。
これ以外にも細かな変更点はたくさんあると思いますが、使いながらまた追記していきます。
ということで、次回の記事からタイトルの [無料][2024年版] のボット開発の内容に入っていきます。
目次 : [無料][2024年版] LINE Messaging API v3 + Python(Flask) でボットを作る
GitHub レポジトリ
older_version
内に、各回時点での app.py
と requirements.txt
があります。
- その0 - v3 での変更点
- その1 - 準備編
- その2 - テストアプリ編
- その3 - 情報検索理論(前編)
- その4 - 情報検索理論(後編)
- その5 - tips 編
- その6 - モジュール化編
- その7 - クラス化編
- その8 - Flex Message 編