I created cat-facts.appspot.com in response to a terrific post by user “frackyou” on reddit - while the image they posted wasn’t a real application and in fact was a joke, I thought it would be fun to recreate the app with some anti-spam precautions added in!
Many LOLs were had and I was inspired to give people the ability to bring out their inner “frackyou”. My goal was simple: let users sign themselves up to receive facts about cats from a “cat fact” service. Just in case any spamming occurred, Twilio provided the awesome ability to also make sure people could easily opt out by texting “STOP” back.
At the time I was using my Macbook, a computer I had yet to use for web programming. It was a unique opportunity to start from scratch and build a website without any prior tools. I had no Eclipse, no GIMP, and a foreign looking Terminal. Within a few hours, I was up and running using Google App Engine, TextMate, Twilio SMS, and a bunch of pics of cats from placekitten.com.
I launched my cat facts app the same night user “frackyou” post hit the reddit front page. My app received over 20,000 visits in its first day live. People were finally able to send their loved ones facts about kittens.
Cat facts was built on a pretty slim web stack (a “web stack” is a set of technologies that will let you build a web site). I used only three tools: a text editor, Google App Engine, and Twilio.
A Text Editor
For most coding, a simple text editor will be your greatest friend. I usually code with emacs in Linux, but I was stuck at home with a Macbook, so I used TextMate. This will make it a lot easier to build a webapp using Google App Engine and Twilio without the hassle of installing and configuring an Interactive Design Editor like Eclipse. Linux users should learn to code in emacs, vi, pico, or gedit. For everyone else, use a standard text editor from below.
Google App Engine
Google App Engine is a terrific way to launch a website with the least headache possible. You sign up and get a free subdomain, free hosting, and awesome scaling abilities right off the bat. Google doesn’t require you to give it your credit card to start, it lets you have a sharable domain, and focus on code design. The best part? If you need to scale later, you can pay for only the resources you are really using up on Google’s machines.
I downloaded the python SDK of Google App Engine for the mac and got a subdomain at appspot.com. I saw that cat-facts.appspot.com was available and instantly had a recognizable and usable domain for my service.
If you’re really new to python, you should check out Learnpython.org, a site that has some great lessons on learning python interactively.
Finally, get up to speed with the awesome tools Google App Engine provides for launching apps at their online tutorial.
Twilio
Twilio is the easiest service to send and receive texts and calls automatically. Twilio is great; not only do they give you a python library that simplifies everything down to one function call, but try it out first for free. Once you upgrade to a number for $1 a month, texts cost just one penny. I ended up sending >18k texts. In addition, subscribers can stop receiving texts by simply texting “STOP” back.
Introduction
There were only four files created to run this application: facts.py, app.yaml, index.py, and index.html. We also needed to include a folder, from twilio, in the same folder where these four files were, so we could access the twilio libraries. Downloading this directory was straightforward; check out https://github.com/twilio/twilio-python for detailed instructions.
facts.py
I started by writing up a small python class called facts.py. It contained only one function, catfacts(), which when called, returned a random cat fact.
app.yaml Next, I wrote up the app.yaml file. This is the file used by Google App Engine to direct incoming requests. I figured I could send all requests to a single python class (called index.py) and this would handle everything.
index.html
I had to create a Django template which would be used to show something on the frontend to cat fact fanatics. I kept it simple: a form to get the phone number, a few kitten images from placekitten.com, and a notice to people how they could stop getting cat facts as well as how they could contact me. For those unfamiliar with Django, the tags are used to show some snippet of HTML in only certain circumstances (i.e. print X if condition1 holds). More information about Django is available at their website, but really only a few Django idioms need be memorized to build web pages with App Engine. At the bottom of the HTML is a snippet of code to provide me with some sweet Google analytics.
index.py
Finally, I wrote the main logic behind the cat facts app. Below is the code in it’s entirety; I get to what each line is for in specific detail in the next part.
Imports
I needed a few libraries to build this app. Among them were the datetime, os, and re modules, which let me work with time, operating system calls, and regular expressions respectively. Next, I imported a few modules that helped me use the App Engine database (google.appengine.ext.db
), the App Engine webapp framework (google.appengine.ext.webapp
), the Django templating system (google.appengine.ext.webapp.template
). From twilio, I only used the TwilioRestClient class in the twilio.rest module (in our twilio/
folder). Finally, I imported the catfacts method.
Utility functions In this code, we only needed one utility function, called last_time()
, which tells us what the time was four hours ago. This was used by our code to find people in the database that we needed to text with fresh cat facts.
Setting up the db I had pretty simple requirements of the database. For each person, I wanted to remember her number and record the last time I sent her a text. I also kept a field called count
that kept a count of how many texts I had sent that person.
Setting up request handling When requests came in, I wanted to check whether the user was submitting a get
or post
request. In the case of a get
request, I basically rendered index.html, passing in only a template value for the “fact” field (e.g. so that a random fact would appear on the front page).
Sanitizing and checking input If a post
request came in, I first checked if the “number” field was part of the request (which I get from self.request.get('number')
). The number must be 10 digits without spaces or hyphens to be submitted to the database (I don’t actually worry about whether or not the number is real. Twilio’s API handles that part). Then, I make a single call to call_people
. Finally, I render a page back to the user to let them know their number has been added (if it has been).
Setting up people to text Rather than run a cron job for App Engine, I decided it might be quicker and to use a single newbie’s request to add a number to both send that newbie a text and some oldies in the database. Thus, I fetched a bunch of people from the database and, along with the newbie, made a call to call_person
.
Texting a person The call_person
method was the real meat of index.py
. Check out the additional resources for a look at how another developer used Twilio with App Engine (his code inspired the design decisions seen here). It turns out, Twilio’s texting lets you create 160 character texts at a time. For this reason, I decided to make the SIZE
variable equal 155, to be able to add the additional information (in the front of the text) about which part of a long text they were looking at. To use the TwilioRestClient, we only needed to import the library at the top of our python code, set up the client with a simple call to TwilioRestClient(account, token)
, and finally send an SMS message using client.sms.messages.create
.
Building this web app was fun and an easy way for me to engage with the terrific community over at reddit. It was quite simple to get this app up and running in a few hours thanks to App Engine, Twilio, and TextMate. If you have any other questions about the site, or about development in general, contact me at twitter (@xoob).