MEric
MEric

Reputation: 966

Facebook Messenger with Flask

I'm trying to get the FB messenger API working using Python's Flask, adapting the following instructions: https://developers.facebook.com/docs/messenger-platform/quickstart

So far, things have been going pretty well. I have verified my callback and am able to receive the messages I send using Messenger on my page, as in the logs in my heroku server indicate the appropriate packets of data are being received by my server. Right now I'm struggling a bit to send responses to the client messenging my app. In particular, I am not sure how to perform the following segment from the tutorial in Flask:

var token = "<page_access_token>";

function sendTextMessage(sender, text) {
  messageData = {
  text:text
}
request({
  url: 'https://graph.facebook.com/v2.6/me/messages',
  qs: {access_token:token},
  method: 'POST',
  json: {
    recipient: {id:sender},
    message: messageData,
  }
}, function(error, response, body) {
  if (error) {
    console.log('Error sending message: ', error);
  } else if (response.body.error) {
    console.log('Error: ', response.body.error);
  }
});
}

So far, I have this bit in my server-side Flask module:

@app.route('/', methods=["GET", "POST"])
def chatbot_response():
    data = json.loads(req_data)
    sender_id  = data["entry"][0]["messaging"][0]["sender"]["id"]
    url = "https://graph.facebook.com/v2.6/me/messages"
    qs_value = {"access_token": TOKEN_OMITTED}
    json_response = {"recipient": {"id": sender_id}, "message": "this is a test response message"}
    response = ("my response text", 200, {"url": url, "qs": qs_value, "method": "POST", "json": json_response})
    return response

However, running this, I find that while I can process what someone send my Page, it does not send a response back (i.e. nothing shows up in the messenger chat box). I'm new to Flask so any help would be greatly appreciated in doing the equivalent of the Javascript bit above in Flask.

Thanks!

Upvotes: 1

Views: 2314

Answers (4)

aluich
aluich

Reputation: 19

This is the Flask example using fbmq library that works for me:

echo example :

from flask import Flask, request
from fbmq import Page

page = fbmq.Page(PAGE_ACCESS_TOKEN)

@app.route('/webhook', methods=['POST'])
def webhook():
  page.handle_webhook(request.get_data(as_text=True))
  return "ok"

@page.handle_message
def message_handler(event):
  page.send(event.sender_id, event.message_text)

Upvotes: 1

Allan
Allan

Reputation: 11

This is the code that works for me:

data = json.loads(request.data)['entry'][0]['messaging']
for m in data:
  resp_id = m['sender']['id']
  resp_mess = {
    'recipient': {
      'id': resp_id,
    },
    'message': {
      'text': m['message']['text'],
    }
  }
  fb_response = requests.post(FB_MESSAGES_ENDPOINT,
                              params={"access_token": FB_TOKEN},
                              data=json.dumps(resp_mess), 
                              headers = {'content-type': 'application/json'})

key differences:

message needs a text key for the actual response message, and you need to add the application/json content-type header.

Without the content-type header you get the The parameter recipient is required error response, and without the text key under message you get the param message must be non-empty error response.

Upvotes: 1

ben author
ben author

Reputation: 2955

In that scenario in your tutorial, the node.js application is sending an HTTP POST request back to Facebook's servers, which then forwards the content on to the client.

So far, sounds like your Flask app is only receiving (AKA serving) HTTP requests. The reason is that that's what the Flask library is all about, and it's the only thing that Flask does.

To send an HTTP request back to Facebook, you can use any Python HTTP client library you like. There is one called urllib in the standard library, but it's a bit clunky to use... try the Requests library.

Since your request handler is delegating to an outgoing HTTP call, you need to look at the response to this sub-request also, to make sure everything went as planned.

Your handler may end up looking something like

import json
import os
from flask import app, request
# confusingly similar name, keep these straight in your head
import requests

FB_MESSAGES_ENDPOINT = "https://graph.facebook.com/v2.6/me/messages"

# good practice: don't keep secrets in files, one day you'll accidentally
# commit it and push it to github and then you'll be sad. in bash:
# $ export FB_ACCESS_TOKEN=my-secret-fb-token
FB_TOKEN = os.environ['FB_ACCESS_TOKEN']


@app.route('/', method="POST")
def chatbot_response():
    data = request.json()  # flasks's request object
    sender_id = data["entry"][0]["messaging"][0]["sender"]["id"]
    send_back_to_fb = {
        "recipient": {
            "id": sender_id,
        },
        "message": "this is a test response message"
    }

    # the big change: use another library to send an HTTP request back to FB
    fb_response = requests.post(FB_MESSAGES_ENDPOINT,
                                params={"access_token": FB_TOKEN},
                                data=json.dumps(send_back_to_fb))

    # handle the response to the subrequest you made
    if not fb_response.ok:
        # log some useful info for yourself, for debugging
        print 'jeepers. %s: %s' % (fb_response.status_code, fb_response.text)

    # always return 200 to Facebook's original POST request so they know you
    # handled their request
    return "OK", 200

Upvotes: 0

TheF1rstPancake
TheF1rstPancake

Reputation: 2378

When doing responses in Flask, you have to be careful. Simply doing a return statement won't return anything to the requester.

In your case, you might want to look at jsonify(). It will take a Python dictionary and return it to your browser as a JSON object.

from flask import jsonify
return jsonify({"url": url, "qs": qs_value, "method": "POST", "json": json_response})

If you want more control over the responses, like setting codes, take a look at make_response()

Upvotes: -1

Related Questions