Monday, January 24, 2011

How-To: SMS Q+A with Twilio, App Engine, and CherryPy

When learning a new API or programming language, I often get a bit nostalgic for the first programs I wrote in BASIC. Those programs looked a lot like this:

10 INPUT "What is your name? "; U$
20 PRINT"Hello, ", U$


To illustrate the simplicity of Twilio, Google's App Engine and CherryPy, I'll take this simple program and show you how to build it for an SMS interface.

Twilio allows you to automate placing and receiving phone calls, and placing and receiving SMS-messages (or TXTs). For this tutorial, we'll focus on placing and receiving SMS-messages. App Engine is a way to inexpensively (free to start) run web applications in Google's cloud. CherryPy is an extremely simple HTTP server for Python. CherryPy has nominal configuration and reminds me a *lot* of the simplicity of the original Java Servlet specification.

Before we get started, you need to signup for Twilio and Google App Engine accounts. Both are free and easy to setup. Once you've done that, swing on back, and we'll walk through the rest.

The Spec

  • A user sends an SMS to your sample Twilio account phone number with the text "?".
  • Twilio sends that request to your new Google App Engine App.
  • Google App Engine dispatches the request to your CherryPy app.
  • CherryPy reads the body of the request.
  • If the request field Body is "?", CherryPy responds with "What is your name?" 
  • If the request field Body is not "?", CherryPy responds with "Hello, [Body]."
  • The user that sent the original SMS message receives the response on their phone.

The Development Process

First, we're going to get a simple app running in CherryPy on your local machine. Then, we'll get it running on  App Engine locally, and in the cloud. Finally, we'll connect Twilio to App Engine and you can watch it all in action.


Get your app running in CherryPy

First, create a directory for your app:
$ mkdir twilio_qa

Download cherrypy

Unzip cherrypy in the twilio_qadirectory.

Then, use your favorite editor to create twilio_qa.py.

#!/usr/bin/env python
import cherrypy

class TwilioQA:
  # the main entry point, this is the method that will get called
  # when someone hits your server.
  def index(self, Body="?", **kwargs):
    if (Body == "?"):
      return self.instructions()
    else:
      return self.wrap("Hello, %s.\r\nShall we play a game?" %Body)

  # print out the instructions
  def instructions(self):
    s = "What is your name?"
    return self.wrap(s)
  
  # helper function to wrap response with twilio SMS Response XML
  def wrap(self, response):
    s = """<?xml version="1.0" encoding="UTF-8" ?>   
<Response>
  <Sms>%s</Sms> 
</Response>
""" % (self.trim(response))
    return s

  MAX_SMS_LENGTH = 160

  # remove all chars after 160, otherwise Twiilo will reject the
  # response.
  def trim(self, s):
    return s[0:self.MAX_SMS_LENGTH]

  # tell cherrypy which methods it can call.
  index.exposed = True

# setup cherrypy
app = cherrypy.tree.mount(TwilioQA(), "/")  
cherrypy.quickstart(app)
Make twilio_qa.py executable and run it.

$ chmod +x twilio_qa.py
$ ./twilio_qa.py

Test your app

With your app running, open a browser and go to http://localhost:8080/.

The page should return the instructions:

What is your name?
Add the parameter for the body to see how it works with a response  http://localhost:8080/?Body=Pete. # Note case for form fields matters, cherrypy automatically maps query paramaters to variables in your index method.

You should see the response:

Hello, Pete. Shall we play a game?
Viewing the source will show you the XML that you will be sending to Twilio in just a little bit.

The cherrypy setup is really simple. You import cherrypy, mount the default URL "/" to your TwilioQA() class, and run the server with the quickstart() method.

Run your app in App Engine

Download and install the App Engine SDK for Python.
Create an app.yml in your twilio_qa directory.
application: twilio-qa-CHANGE-ME
version: 1
runtime: python
api_version: 1

handlers:
- url: /.*
  script: twilio_qa.py

In twilio_qa.py, import wsgiref.handlers to work with appengine:

...
import cherrypy
import wsgiref.handlers
...

In twilio_qa.py, comment out quickstart and add the App Engine handler:
... 
app = cherrypy.tree.mount(root, "/")
# cherrypy.quickstart(app)
wsgiref.handlers.CGIHandler().run(app)

Run your app in app engine's localserver:

$ dev_appserver.py --port=8080 ../twilio_qa/

Follow the steps in Test your app and scroll back here when you're done.

Deploy on App Engine

Now that you've tested locally, you can deploy to the cloud in a few easy steps.


Create a new application at appengine.google.com:
  1. Click [Create Application].
  2. Choose an [application identifier] (you'll use this for the application field in app.yml later). This needs to be unique across the entire appspot.com domain. Good luck :-)
  3. Create a title.
  4. Update your app.yml, set your application identifier as the value in application.
  5. Deploy your app by typing:
    $ appcfy.py update ../twilio_qa/
  6. Go test your app, instead of localhost, substitute http://[your-application-id].appspot.com/ for http://localhost:8080

For more on appengine, definitely check out their great knowledge base for getting started in Python.

Connect to Twilio

Now that you have your twilio trial account and your app ready to be connected, you just need to connect the 2.

In the Developer Tools section of your account, set you SMS URL to:

http://[your-application-id].appspot.com/

Click [Save].

Send a TXT to the Sandbox Phone Number you configured with the Body of "[PIN] ?".

You'll need to put the [PIN] in for the next question as well.


The end

Go forth and create inexpensive Question and Answer apps using SMS, Twilio and App Engine.

If you have any questions, issues, or create something awesome with this tutorial, please drop me an a comment.