0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Facebook Messenger API + Flask 備忘録 [実装編 1]

Last updated at Posted at 2020-12-12

導入編 からの続き、とりあえず簡単なオウム返しから。

pymessenger というサードパーティー製のライブラリもあるようだが、2016年から更新されていないので、勉強も兼ねて今回は自分で実装する。

POSTリクエストの中身

詳しくはこちら: Webhook Events, Send API

全部読むのは面倒なので、必要な部分だけ使いながら実装していく。

API の webhook の本体はこんな感じ。まずはユーザーがアプリに送信した場合

{
  'object': 'page',
  'entry': [
    {
      'id': '<FBページのID>',
      'time': 1607767826503,
      'messaging': [
        {
          'sender': {
            'id': '<FBユーザーのID>'
          },
          'recipient': {
            'id': '<FBページのID>'
          },
          'timestamp': 1607767826302,
          'message': {
            'mid': 'xxxxxxxxxxxxxxxxxxxxx',
            'text': 'hello'
          }
        }
      ]
    }
  ]
}

自分のページ側のIDは既に知っているので取得する必要はない。つまり ['entry']['messaging'] の中の ['sender']['id'] および ['message']['text'] を取り出せば良い。ここで ['entry'] はイベントの配列、 ['entry']['messaging'] はメッセージの配列になっているので for 処理などが必要。とは言っても、試した限りでは未受信のメッセージが溜まっていても同時にまとめて送られることはなく、一件のみだった。

また、メッセージの直後にほぼ同じ形式でウォーターマークが送られる。こちらには ['message'] の代わりに ['delivery'] がある。

{
  'object': 'page',
  'entry': [
    {
      'id': '<FBページのID>',
      'time': 1607767829878,
      'messaging': [
        {
          'sender': {
            'id': '<FBユーザーのID>'
          },
          'recipient': {
            'id': '<FBページのID>'
          }, 
          'timestamp': 1607767829912,
          'delivery': {
            'mids': [
               'xxxxxxxxxxxxxxx'
             ],
             'watermark': 1607767827879
          }
        }
      ]
    }
  ]
}

一方返信用の中身はこれだけで十分。これに発行したトークンを access_token としてパラメータで与え、ヘッダーに Content-Type: application/json を指定すればOK。

{
  "recipient": {"id": "<FBユーザーのID>"},
  "message": {"text": "hello"}
}

おうむ返し実装

前回のコードに、POST 部分を追加する。後々のことを考えて、send_message() という関数を分けて作っておく。

ちなみにここで取得した userID というものは、FacebookアカウントのIDとは全く別物で、Page-scoped ID と呼ばれるらしい。自分のIDを知るためにも、返信文の中に埋め込む。

import os, json
from flask import Flask, request
from dotenv import load_dotenv
load_dotenv() # 環境変数ファイル .env の読み込み
ACCESS_TOKEN = os.getenv('ACCESS_TOKEN') # .env に記載
VERIFY_TOKEN = os.getenv('VERIFY_TOKEN') # .env に記載

@app.route('/callback', methods=['GET', 'POST'])
def receive_message():
    if request.method == 'GET': # webhook テスト用 GET
        if request.args.get("hub.verify_token") == VERIFY_TOKEN:
            return request.args.get("hub.challenge")
        else:
            return 'ちがうよ'
    elif request.method == 'POST': # POSTリクエスト -> 返信処理
        body = request.get_json() # 中身取得 
        for entry in body['entry']: # iterate 'entry'
            for messaging in entry['messaging']: # iterate 'messaging'
                userID = messaging['sender']['id'] # ユーザーのID
                if messaging.get('message'): # メッセージ以外を除外
                    received_message = messaging['message']['text'] # テキスト
                    response = f'{userID}さん, {received_message}' # おうむ返し文
                    send_message(userID, response) # 返信実行
        return "finished" # なんでも良い。返信内容とは無関係だが、無いとエラーになり返信を繰り返す

# 返信リクエスト用関数
# 失敗したらログに出力, Heroku なら heroku logs --tail で確認可
def send_message(userID, message): 
    result = requests.post("https://graph.facebook.com/v9.0/me/messages",
        params={"access_token": ACCESS_TOKEN},
        headers={"Content-Type": "application/json"},
        data=json.dumps({
            "recipient": {"id": userID},
            "message": {"text": message}
        })
    )
    if result.status_code != 200:
        print('送信失敗だよ:', data)

とりあえずこれで、このようなおうむ返しが可能になる。

Screen Shot 2020-12-12 at 7.17.53 PM.png

POST テスト

メッセージの送信テストをする際に、いちいち Python のプログラムをデプロイするのは非常に面倒なので、専用のツールを使って試したい。

Facebook はブラウザ上で API の動作を試せる Graph API Explorer なるものをわざわざ作ってくれておりこれだけでもいろいろできるのだが、やはり保存したり再利用したりすることを考えて、ド定番のリクエストツール Postman を利用する。

POST を選んで URL に https://graph.facebook.com/v9.0/me/messages
Params の KEY に access_token, VALUE に発行した長いアクセストークンを入力
Screen Shot 2020-12-12 at 6.14.26 PM.png
Headersは Content-Typeapplication/json
Screen Shot 2020-12-12 at 6.16.17 PM.png
最後に Body は raw を選んで、送りたいメッセージを json 形式で記入する。先ほどのプログラムで取得した自分のIDを入力する。
Screen Shot 2020-12-12 at 6.18.06 PM.png

このように、簡単にメッセージを送信できる。これ自体は上で実装した関数 send_message() を用いてももちろん可能。

Screen Shot 2020-12-12 at 7.29.58 PM.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?