Build your first Facebook Messenger bot in Ruby with Sinatra and “facebook-messenger” gem (Part…

7,215 reads

Here is the Part 1 of making a simple Facebook bot that harnesses the power of Google Maps Geocoding API. In Part 2 we will add more features, refactor the code, and make everything DRYer. In Part 3 we will deploy our bot to Heroku and enhance its interface.

An obscure cultural reference for Soviet-born readers

This tutorial assumes you already have a usual Ruby environment installed on your machine and you are aware of the brave new world Ruby gems give us. Here’s a preview of what we are going to build by the end of the second part:

Cool, huh?

Preface

Let’s face the inconvenient truth. Bots are overhyped, mainly because they are still dumb. The majority of them. I am 32 years old, excited about all things digital since the age of 15, and I learned my speed typing on IRC. It is the chat service that first appeared in 1988 and anticipated the World Wide Web by a good year or two. By the time web chatrooms became a thing, IRC already had a global community of hackers. I met at least two of my current best friends there, when I had my own channel on DALnet named #402. Yes, it had channels that started with the hash sign (I look at you, Slack, kudos for reviving a 25 years old tech). It also had bots.

Old is the new young, as seen by Google Trends

So no wonder when bots became a household word again in 2016, my friends and I just shrugged. Of course, when you add some serious AI voodoo, bots can achieve amazing feats. But, seriously, let’s be honest with each other, my fellow developers: your average hyped-up bot is not much smarter than a Perl script that ran on IRC server in 2002.

A bot-related prehistoric meme circa 1995

All that considered, I still believe bots are great and they are going to be big. Even if they never smarten up. Why so? Bots can take a lot of heat off the front end and reduce developing cost for the apps as developers can focus on business logic, not looks. JavaScript community is a mess now, new front-end framework appears every other week, and any more or less decent modern interface would require a rock-star programmer, who happens to also be a designer and an UX-engineer. While it’s good news for smart guys, it’s bad news for those who have to hire more of them just to look well.

Meet bots. As you will see shortly, you just need a micro-framework and a back end language of choice (surely, it can be JS as in NodeJS) to quickly build an interactive app. And it may actually engage users, if you do something useful with it.

Enough talk, let’s build one

Frank Sinatra after a certain Ruby framework stole his name and his hat

As much as I want to use some more Rails (I started learning it less than three months ago at Le Wagon bootcamp in Paris and have only made two student projects with it), our weapon of choice will be Sinatra — and the following screenshot is the reason why.

Folder structure of a Rails app (right) vs. the structure of a Sinatra app (left)

Sinatra allows you to create a functioning web app in just few lines of code, without any boilerplate. In our example, we will only need Sinatra to do one specific thing, the rest will be handled by the incredible facebook-messenger gem, created by some genius guys in Oslo.

Go to your console and type:

gem install facebook-messenger

The bot runs on Rack, same as Sinatra (and Rails, for that matter). So, in order to start, we will need a rackup file. Create a folder for your project (mine is named coordinator-bot) and place a file named config.ru in it. .ru stands for rack-up (and a top-level internet domain for Russian Federation). Put this inside:

Next, create a file named app.rb in the same folder and put in the following:

Next, create another file, called Gemfile, with this content:

Now go to your command line and run:

bundle install

OK, time to create our app on Facebook

Up until now, you were a Facebook user, now it’s time to become a Facebook developer. Go to https://developers.facebook.com/, login with your usual Facebook account and in the top right corner of the screen pick “Add a new app”.

Enter your app name (use your fantasy!) and don’t forget to set a category as “Apps for Messenger”.

Facebook then will make sure you are not a robot, which is ironic, but avoids Skynet scenario. Then, under “Token generation” pick “Create new page” and pick a category. Mine was “Brand or Product”.

Skip everything in a wizard menu (of course, if you want to make your test page look nice, be my guest!), go back to your developer’s dashboard and generate a token for the new page.

Save it somewhere on your computer (but don’t give to anyone or post publicly!), you will need it in a moment.

You will have two things from your Facebook dashboard that you are supposed to keep secret. Your page token (we’ll call it ACCESS_TOKEN) and the token for webhook verification (VERIFY_TOKEN). Page token was just generated and the verification token can be anything you want, just make sure to remember it later. Next, open another tab in your Terminal and type export ACCESS_TOKEN= and export VERIFY_TOKEN=, while using your own values after the “=“ sign (also, note there are no quotes around tokens). That is called setting environment variables.

With Rails this sort of thing would be handled by Figaro gem, but I couldn’t make it work under Sinatra, my best guess: it’s not supported (feel free to correct me in comments)

NB! Comment out require_relative 'bot' from your config.ru file before you proceed. You will need to put this line back when we actually create a bot file, but for now, just to test that rackup is working, we will need to temporarily disable it.

It’s time to start our servers. Go back to the command line from inside your project folder (Note! it should be the same Terminal tab you just typed your environment variables in) and type this:

rackup -p 5000

You should see this:

You can pick another port number (1337, anyone?), but it should be the same as the one we will pipe through Ngrok. Go to Ngrok’s website, download it and put the executable inside your project folder or one of its parents. Then you can run it like so (in a new tab).

./ngrok http 5000

With this effect:

Now your whatever happens on the port 5000 on your localhost will be seen broadcasted on The Internet under a domain name that will be generated uniquely for you and will resemble something like this: http://982bd57f8.ngrok.io.

Go to this address in your browser: you should see the text “Nothing to see here”. That’s right, that’s what these lines in our app.rb were about:

In your Facebook dashboard, where you just generated the access token for your Facebook page, scroll a bit down and under “Webhooks” click “Setup Webhooks”. Switch to your terminal (you ran that ./ngrok command in a new tab, right?), copy the URL under “Forwarding” (make sure you copy the one that starts with https://) and attach /webhook to it. This is how we named a path under which our server will communicate with Facebook. We could call it /bot — it’s up to you. Under “Verify Token” put the same string you came up with earlier while setting your environment variables. Tick the “messages” mark.

Now you can click “Verify and Save”. If you set up your server correctly, Facebook will call /webhook path on your ngrok URL, send you a ‘challenge’ (which is just a random string of digits) and wait for it to be echoed back. These lines in app.rb do it:

That was actually all we needed Sinatra for. Moving on.

Bot, meet your maker

All further programming will be done inside our bot.rb file. Go ahead and create one in your project folder. Your first bot will just say “Hello!” to whatever humans send him.

Remember, every time you change something in any of your files you have to go back to the terminal tab where your rack server is running (you can leave ngrok alone), hit Ctrl-C and restart it. Also, now you will need to require_relative ‘bot’ in your config.ru

Now open your Facebook Messenger (whether desktop or mobile), find your bot by using your recently created page name under “Search Messenger” and type anything. He will respond “Hello!”.

Congratulations, you’ve just had a first conversation with your own bot!

In your server tab you should see something like:

"POST /webhook HTTP/1.1" 200 - 0.0011

That means bot had sent an HTTP POST request to your server on its /webhook path and the server (facebook-messenger gem) replied accordingly. You can add this line at the beginning of the Bot.on block.

Bot.on :message do |message|

puts "Received '#{message.inspect}' from #{message.sender}"

(…rest of the code in bot.rb)

It will let you learn more about the conversation your bot is having, your server tab will log something like this:

Okay, your bot is not particularly smart at this point. Let’s add some real world functionality. How about bot giving you GPS coordinates for any address in the world when you type it it? We’ll use Google Maps Geocoding API. All you need is to send a GET request (you should also put your private API key at the end of the URL, but for testing we can get away without one, check Google’s doc for more info on API keys):

Google will do its magic (for example, it will figure out that you want Moscow, Russia, not Moscow, Texas, if you connect with a Russian provider) and it will send back a JSON that contains all sort of useful data, namely the latitude and the longitude.

We will use an amazing HTTParty gem to make our requests. We already installed it in our project during the initial bundle install. Add this method to your bot.rb

We use Ruby’s standard JSON parsing functionality to turn response from API into a regular Hash object. Make sure your bot.rb has the line require ‘json’ at the top.

Now dig inside the hash to find our coordinates. Add this method to bot.rb.

Update your Bot block to send back the data you got from the API. Replace your Bot.on method with this:

In the end your bot.rb should look like this:

Great! Go ahead and test your bot! It should do this.

YAY! Our first bot that makes sense!

Right now our bot is still very stupid. It only can spit back coordinates to you when you enter a valid address. No hellos, no good-byes. If you type something Google can’t find, it will just hang and you will have to restart your Rack.

In the Part 2 of this tutorial we will make our bot smarter and it will be able to keep up with a simple conversation. We will also handle the case where API does not return any results, and we will teach it to to look up the full postal address lookup for any location.

That’s all for now. I hope you enjoyed it!

All the code for our bot at this stage of its development can be found on my Github.

You can find the code for a final project (still WIP on the time of this writing) in the same repo, but in the main branch. Feel free to fork it, clone it and play with it.

Disclaimer: I’m a beginner web developer, ex senior international TV correspondent, and young father with zero (nil, null, zilch) experience in IT. Aside from obsessing about coding style and trying to pump my head full of technical literature while looking for my first serious dev gig, I recently graduated top of the class from an excellent Le Wagon coding bootcamp in Paris and co-authored Halfway.ninja as a graduate project there. It’s an airfare comparator for couples. Go check it out! You can find me on Github, Twitter and Instagram. I also own this domain. I am also available for hire, be it an inspiring internship, freelance or even full-time work. I speak English, Russian, French, Ruby, JavaScript, Python and Swift and I am currently based in Moscow, Russian Federation. Feel free to write me directly with any offers (or death threats).

Tags