# Lab 1 - Messenger Platform ## Step 0 - Set up Facebook Account > https://developers.facebook.com/docs/messenger-platform/getting-started/app-setup You'll need the first three things, which will be self-explanatory. > 1. Facebook Page: A Facebook Page will be used as the identity of your Messenger experience. When people chat with your app, they will see the Page name and the Page profile picture. To create a new Page, visit https://www.facebook.com/pages/create > 1. Facebook Developer Account: Your developer account is required to create new apps, which are the core of any Facebook integration. You can create a new developer account by going to the Facebook Developers website and clicking the 'Get Started' button. > 1. Facebook App: The Facebook app contains the settings for your Messenger experience, including access tokens. To create a new app, visit your app dashboard The fourth, we'll set up here. ## Step 1 - Setting up Vercel / Ngrok / HTTP Endpoint The first step is to just simply create and deploy something to the internet, that returns "Hello World". In the next step, we will make it respond correctly to Facebook's webhooks. We'll use two services here, [ngrok](www.ngrok.com) and [Vercel](www.vercel.com) to aid us in our mission. We'll start by installing Vercel - [detailed instructions here](https://vercel.com/download). `npm i -g vercel` 1. Create a new directory for your project, and inside the project, create a directory called `api` and a file called `hello.js`. `npm init -y` `mkdir api` `touch api/hello.js` As mentioned above, we'll simply return "Hello World". ``` export default (req, res) => { res.send("Hello World") } ``` This is using Vercel's serverless Node runtime, which is based off of Express / NodeJS. You can find [documentation here](https://vercel.com/docs/serverless-functions/introduction). If you aren't familiar with Express, don't worry, we won't use any advanced features of the framework here. But if you're curious [you can explore express documentation here](https://expressjs.com/en/starter/hello-world.html). Make sure you're in the root directory (not in `/api`): ![](https://i.imgur.com/nWCBHko.png) The basic settings should be fine: ![](https://i.imgur.com/Plq4C99.png) You can now go to the URL, in my case: https://msngr-hl-wrld.vercel.app/api/hello This is important to get a real address on the internet, because Facebook needs to be able to call our bot, so "localhost" won't be sufficient. We could stop here and keep uploading each time (`npx vercel` will deploy a new version) but this is pretty inconvenient, because it's quite slow to deploy each time. This may not seem like a big deal but over time this will be super frustrating and slow us down too much. Instead, let's develop on localhost. First step is to run vercel in development mode, by typing: ``` vercel dev ``` ![](https://i.imgur.com/Blm2ZpT.png) This starts at a local port, 3000. But now we need a way for Facebook to reach our local port, 3000. There are many options here, but let's start with a service called https://ngrok.com/. You'll want to sign up (don't worry, we'll stay on free tier) and https://dashboard.ngrok.com/get-started/setup. You'll download this, and then you'll unzip it - it's just an executable. After you download it, you just need to run: ``` ./ngrok http 3000 ``` This will give you an externally available address that _forwards_ to your local computer: ![](https://i.imgur.com/OxhIhMX.png) Verify that going to your ngrok URL successfully returns "Hello World". ## Step 2 - Setting the Verify webhook callback for Facebook Now we can go to the next steps in the Facebook setup: https://developers.facebook.com/docs/messenger-platform/getting-started/app-setup. Add Webhooks and Messenger to your Facebook App, and you'll be prompted for a callback URL. Use your ngrok from the previous step. **NOTE**: every time you restart ngrok, you'll need to update this URL because your ngrok url will change. (In production, you can point it at your Vercel production instance.) ![](https://i.imgur.com/Ylpx0rV.png) You can set the Verify Token to whatever you like. It is your personal password, and just remember it. Your callback url needs to come back with the right parameters - if you haven't coded your server correctly (which we haven't), when you try to put "Verify and Save", you'll get an error like this: ![](https://i.imgur.com/MypcZBx.png) or possibly like this: ![](https://i.imgur.com/4rhXjTO.png) We actually need to fix two things - our path, and our code. * Create a new file, let's call it `webhook.js`. That file looks like this: ``` module.exports = (req, res) => { if (req.method == "GET") { return verifyWebhook(req, res); } return handlePost(req, res); }; const verifyWebhook = ({ query }, res) => { // Your verify token. let VERIFY_TOKEN = "ToiYeuDevC"; // Parse the query params let mode = query["hub.mode"]; let token = query["hub.verify_token"]; let challenge = query["hub.challenge"]; // Checks if a token and mode is in the query string of the request if (mode && token) { // Checks the mode and token sent is correct if (mode === "subscribe" && token === VERIFY_TOKEN) { // Responds with the challenge token from the request console.log("WEBHOOK_VERIFIED"); res.status(200).send(challenge); } else { // Responds with '403 Forbidden' if verify tokens do not match res.status(403).send(); } } }; const handlePost = (req, res) => {}; ``` Note that I wrote `ToiYeuDevC`; that can be anything (but just make it the same as what you put in the Facebook dialog). Now change your url to `xxx.ngrok.io/api/webhook`, and then clicking "Verify and Save" will succeed and you've made it to the next step! Now click on the Messenger Tab and make sure to subscribe to `messages` and `messaging_postbacks`. ![](https://i.imgur.com/e9Tazik.png) ## Step 3: Receive Messages! The `verifyWebhook` code is just to let Facebook know that our server is indeed, the right one (so nobody else can take over our chatbot). The real magic happens in `handlePost`; that's where our subscriptions will trigger. Here, we'll share code that's a highly simplified version of the official facebook samples at https://github.com/fbsamples/messenger-platform-samples/tree/master/quick-start and https://github.com/fbsamples/original-coast-clothing. Please read those! But I think you'll find that CoderSchool's version is simpler ;). For `handlePost`: ``` const handlePost = (req, res) => { let body = req.body; // Checks if this is an event from a page subscription if (body.object === "page") { // Returns a '200 OK' response to all requests res.status(200).send("EVENT_RECEIVED"); // Iterates over each entry - there may be multiple if batched for ({messaging} of body.entry) { const { sender, message } = messaging[0]; console.log('sender', sender); console.log('message', message) } } }; ``` Now send your bot a message. You won't see a response, but you _will_ see something pop up in your local terminal (where you ran `vercel dev`). ![](https://i.imgur.com/k26kHkA.png) **Hooray**, messages are getting through to your program. ## Step 3: Respond with a Simple Text Message Now it's time to make your robot come to life. We'll need to reply to the `post` requests. To make things easier, let's install the popular `axios` library that makes HTTP requests easier: ``` npm install axios ``` Now we'll need At the top of webhook.js ``` const axios = require('axios'); ``` Now, in the handlePost, after the `console.log`s of the previous step: ``` const token = <INSERT TOKEN HERE> const handlePost = (req, res) => { let body = req.body; // Checks if this is an event from a page subscription if (body.object === "page") { // Returns a '200 OK' response to all requests res.status(200).send("EVENT_RECEIVED"); // Iterates over each entry - there may be multiple if batched for ({ messaging } of body.entry) { const { sender, message } = messaging[0]; console.log("sender", sender); console.log("message", message); if(!message) { return; } axios.post( `https://graph.facebook.com/v8.0/me/messages?access_token=${token}`, { recipient: { id: sender.id }, message: { text: `Hi! I've received your message ${message.text}` } } ); } } }; ``` You'll see we need a token. Where did this come from? Well, it comes from your "Page access tokens" on Facebook settings. ![](https://i.imgur.com/9xFFnO7.png) Click the generate token, and you'll get a token. Replace `<YOUR TOKEN HERE>` with your token. Make sure you keep this token secret (don't upload it into git). For full credit, you should set this as an environment variable - you [can consult vercel documentation here](https://vercel.com/docs/build-step#environment-variables) but we won't cover that here. Now we've set up our "parrot" bot, which will repeat what you say. ![](https://i.imgur.com/uy0Tyb3.png) ## Step 4: Send a Structured Message Plain text responses already open up a lot of possibilities, but here's one more: using what's called a "message template". Instead of simply replying with `{text: blahblah}` we can respond with a "structured" message, with buttons. Create a message: ``` const response = { "attachment": { "type": "template", "payload": { "template_type": "generic", "elements": [{ "title": "Do you love DevC?", "subtitle": "Tap a button to answer.", "image_url": 'https://www.techsignin.com/wp-content/uploads/2019/05/facebook-developer-circles-vietnam-innovation-challenge-22.jpg', "buttons": [ { "type": "postback", "title": "Yes!", "payload": "yes", }, { "type": "postback", "title": "No!", "payload": "no", } ], }] } } } ``` Now, from the previous step, replace sending ``` message: { text: `Hi! I've received your message ${message.text}` }, ``` with: ``` message: response, ``` and you should get something like this: ![](https://i.imgur.com/uDLmJR8.png) ## Step 5: Responding to the Button Click (postback) Note that responding to the message doesn't do anything. Buttons come in the form of `messaging_postbacks`, which we subscribed to earlier. To handle this, let's refactor our code to read the `postback` field, and separate our handling. ``` for ({ messaging } of body.entry) { const { sender, message, postback } = messaging[0]; console.log("sender", sender); console.log("message", message); console.log("postback", postback); if(postback) { return handlePostback(sender, postback); } if(message) { return handleMessage(sender, message); } ``` Copy the previous code into handleMessage. Let's now implement `handlePostback`. We will read the `payload` we specified above: ``` const handlePostback = (sender, postback) => { console.log('postback2', postback); if(postback.payload == "yes") { axios.post( `https://graph.facebook.com/v8.0/me/messages?access_token=${token}`, { recipient: { id: sender.id }, message: {text: "thanks! devc loves you too"}, } ); } if(postback.payload == "no") { axios.post( `https://graph.facebook.com/v8.0/me/messages?access_token=${token}`, { recipient: { id: sender.id }, message: {text: "it's okay, we can still be friends"}, } ); } } ``` ![](https://i.imgur.com/PZ9wwzm.png) **NOTE**: It looks like the user is just typing "Yes!" but it's from clicking on the button. Let's do a little refactoring on the `axios.post` and everything, so here's the cleaner final code: ``` const sendMsg = (recipient, message) => { axios.post( `https://graph.facebook.com/v8.0/me/messages?access_token=${token}`, { recipient, message, } ); }; const handlePostback = (sender, postback) => { if (postback.payload == "yes") { sendMsg(sender, { text: "thanks! devc loves you too!" }); } if (postback.payload == "no") { sendMsg(sender, { text: "it's okay we can still be friends!" }); } }; ```