Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Edit Copy

  • Loading branch information...
commit 0a1171764c5e91edba2189b95f2906948054c878 2 parents 9733549 + ca8d5a1
@etsai etsai authored
View
4 callcenter.py
@@ -56,9 +56,7 @@ def get(self):
resp = twiml.Response()
resp.say("You are being enqueued now.")
- resp.enqueue(self.request.params.get('queue', 'support'),
- waitUrl='/twiml/wait', waitMethod='GET')
- resp.sms("Thanks for calling into today. How was your call?")
+ resp.enqueue('radio-callin-queue')
self.response.write(str(resp))
View
BIN  docs/_static/startapp.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
19 docs/browser.rst
@@ -195,9 +195,9 @@ Change your application's Voice URL so it serves this TwiML when dialed.
Getting the Next Caller From the <Queue>
-----------------------------------------
-With <Queue>s, we can hangup on the current caller and move to the next one by
-pressing the "#" key on the phone. Luckily, Twilio Client has a feature for
-sending DTMF tones programmatically.
+We want to make it easy to hangup the current call and move to the next one by
+pressing the "#" key on the phone. Twilio Client has a feature for sending DTMF
+tones (the tone when you press "#" on your phone) programmatically.
First, we need to hold on to the response of ``Twilio.Device.connect()`` so
let's add a global variable called ``connection`` and have every ``call()``
@@ -288,3 +288,16 @@ into the page.
getQueueStatistics();
});
+Advanced Features
+------------------
+
+That is the end of the content for this tutorial. If you still have some time,
+try implementing some of these advanced features:
+
+- Add a chart showing the wait time of each queue participant.
+- Allow users to call in to the DJ hotline using their browser.
+- Add `a "whisper" URL`_ to play instructions to the DJ before her call
+ connects.
+
+.. _a "whisper" URL: http://www.twilio.com/docs/api/twiml/client#attributes
+
View
202 docs/callin.rst
@@ -5,8 +5,12 @@ Radio Call In
In this workshop we'll be designing a radio call in application using Twilio's
<Queue> functionality. While we'll be using a radio show as our target, this
-style of queue management can be used for any phone number where many people may
-call at the same time.
+style of queue management can be used for any phone number where many people
+may call at the same time.
+
+There will be two numbers, one for calls coming in and one for the DJ. The DJ
+will call in to connect to the waiting callers one at a time. Once the DJ is
+finished with a caller, he or she will press # to move onto the next caller.
Prerequisites
-------------
@@ -18,6 +22,8 @@ Also, we assume you are comfortable writing web applications. For
reference, we'll be developing the application along the way using Python
and Google App Engine.
+Make sure you have a second Twilio number.
+
Using the Twilio Helper Libraries
---------------------------------
@@ -50,6 +56,27 @@ into a queue named ``radio-callin-queue``. Note that queues are created on
<Enqueue>radio-callin-queue</Enqueue>
</Response>
+Here is an example App Engine application that serves the above TwiML.
+
+.. code-block:: python
+
+ import webapp2
+ from twilio import twiml
+
+ class EnqueueHandler(webapp2.RequestHandler):
+
+ def get(self):
+ self.response.headers['Content-Type'] = 'application/xml'
+
+ resp = twiml.Response()
+ resp.say("You are being enqueued now.")
+ resp.enqueue("radio-callin-queue")
+ self.response.write(str(resp))
+
+ app = webapp2.WSGIApplication([
+ ('/twiml/enqueue', EnqueueHandler),
+ ], debug=True)
+
We are going to use a TwiML Application to connect this TwiML with
your listener queue number. We'll need to create an `Application
<http://www.twilio.com/docs/api/rest/applications>`_ for the browser to call
@@ -58,15 +85,14 @@ entry point for incoming calls. Configure the Voice URL of your new Application
to point to the TwiML above.
You want to connect your listener queue function to your Application. From the
-`Numbers <https://www.twilio.com/user/account/phone-numbers/incoming`_ tab of
+`Numbers <https://www.twilio.com/user/account/phone-numbers/incoming>`_ tab of
your Dashboard, select the number you are going to use for your Listener Queue.
Then from the dropdown select "Application", then point to your new
Application.
.. image:: _static/application.png
-Go ahead and try calling your number now to make sure everything is configured
-correctly.
+Go ahead and try calling your number now. You should hear wait music.
We can spice up our TwiML endpoint by adding some wait music, using the
``waitUrl`` parameter.
@@ -75,30 +101,82 @@ We can spice up our TwiML endpoint by adding some wait music, using the
<?xml version="1.0" encoding="UTF-8"?>
<Response>
- <Enqueue waitUrl="/wait-loop">radio-callin-queue</Enqueue>
+ <Say>You are being enqueued now.</Say>
+ <Enqueue waitUrl="/twiml/wait" waitMethod="GET">
+ radio-callin-queue
+ </Enqueue>
</Response>
-Twilio will request the ``/wait-loop`` and process the TwiML there, which plays
+Twilio will request the ``/twiml/wait`` and process the TwiML there, which plays
music. The ``waitUrl`` TwiML document only supports a `subset of TwiML verbs`_,
including ``<Say>`` and ``<Play>``.
+.. code-block:: python
+ :emphasize-lines: 12
+
+ import webapp2
+ from twilio import twiml
+
+ class EnqueueHandler(webapp2.RequestHandler):
+
+ def get(self):
+ self.response.headers['Content-Type'] = 'application/xml'
+
+ resp = twiml.Response()
+ resp.say("You are being enqueued now.")
+ resp.enqueue("radio-callin-queue",
+ waitUrl="/twiml/wait", waitMethod="GET")
+ self.response.write(str(resp))
+
+ app = webapp2.WSGIApplication([
+ ('/twiml/enqueue', EnqueueHandler),
+ ], debug=True)
+
+The ``/twiml/wait`` endpoint will return TwiML that plays hold music for the queue
+
.. code-block:: xml
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Please hold.</Say>
<Play>http://com.twilio.sounds.music.s3.amazonaws.com/MARKOVICHAMP-Borghestral.mp3</Play>
+ <Redirect/>
</Response>
-You can use this Python snippet with AppEngine to render the XML above.
+We use redirect? Once the hold music has finished, Twilio will re-request the
+page and make sure the music doesn't stop.
+
+You can use this Python snippet with AppEngine to output the TwiML above.
.. code-block:: python
+ :emphasize-lines: 9-20, 24
- import webapp2
- class WaitLoopPage(webapp2.RequestHandler):
+ import webapp2
+ from twilio import twiml
+
+ class EnqueueHandler(webapp2.RequestHandler):
+
+ def get(self):
+ # Same as above
+
+ class WaitHandler(webapp2.RequestHandler):
+
+ def get(self):
+ self.response.headers['Content-Type'] = 'application/xml'
+
+ resp = twiml.Response()
+ resp.say("Please hold.")
+ resp.play("http://com.twilio.music.rock.s3.amazonaws.com/nickleus_-_"
+ "original_guitar_song_200907251723.mp3")
+ resp.redirect()
+
+ self.response.out.write(str(resp))
+
+ app = webapp2.WSGIApplication([
+ ('/twiml/enqueue', EnqueueHandler),
+ ('/twiml/wait', WaitHandler),
+ ], debug=True)
- def get(self):
- self.response.out.write(render_template("waitLoop.xml", params))
Now your listener queue number should play hold music while callers are in the
queue.
@@ -120,9 +198,50 @@ by using the <Enqueue> verb.
You will want to create a second Twilio Application for your DJ number, and
configure that application's Voice URL to point to the TwiML above.
+.. code-block:: python
+ :emphasize-lines: 14-24, 28
+
+ import webapp2
+ from twilio import twiml
+
+ class EnqueueHandler(webapp2.RequestHandler):
+
+ def get(self):
+ # Same as above
+
+ class WaitHandler(webapp2.RequestHandler):
+
+ def get(self):
+ # Same as above
+
+ class DequeueHandler(webapp2.RequestHandler):
+
+ def get(self):
+ self.response.headers['Content-Type'] = 'application/xml'
+
+ resp = twiml.Response()
+ d = resp.dial()
+ d.queue("radio-callin-queue")
+
+ self.response.out.write(str(resp))
+
+
+ app = webapp2.WSGIApplication([
+ ('/twiml/dequeue', DequeueHandler),
+ ('/twiml/enqueue', EnqueueHandler),
+ ('/twiml/wait', WaitHandler),
+ ], debug=True)
+
+
Now, the DJ can call the DJ dequeuing number, and will automatically be
connected to the first member on the queue.
+By now, you may be wondering how to properly test this application. With two
+phone numbers, you need to fill up your queue with waiting callers. To help you
+fill your queue, we've created an application that will call a given number
+with fake callers, allowing you to easily simulate real users calling in. The
+application can be found at http://queuetester.herokuapp.com/.
+
.. _subset of TwiML verbs: http://www.twilio.com/docs/api/twiml/enqueue#attributes-waitUrl
Dynamic Queue Information
@@ -152,18 +271,35 @@ Utilizing this information, we can inform our users what position they are in
the queue and how long they can expect to wait before an answer.
.. code-block:: python
+ :emphasize-lines: 9-16
- import webapp2
- from twilio import twiml
+ import webapp2
+ from twilio import twiml
- class WaitLoop(webapp2.RequestHandler):
- def post(self):
- response = twiml.Response()
- response.say("You are number %s in line." % self.request.get('QueuePosition'))
- response.say("You've been in line for %s seconds." % self.request.get('QueueTime'))
- response.say("The average wait time is currently %s seconds." % self.request.get('AverageQueueTime'))
- response.play("http://com.twilio.music.rock.s3.amazonaws.com/nickleus_-_original_guitar_song_200907251723.mp3")
- self.response.out.write(str(response))
+ class EnqueueHandler(webapp2.RequestHandler):
+
+ def get(self):
+ # Same as above
+
+ class WaitHandler(webapp2.RequestHandler):
+ def post(self):
+ response = twiml.Response()
+ response.say("You are number %s in line." % self.request.get('QueuePosition'))
+ response.say("You've been in line for %s seconds." % self.request.get('QueueTime'))
+ response.say("The average wait time is currently %s seconds." % self.request.get('AverageQueueTime'))
+ response.play("http://com.twilio.music.rock.s3.amazonaws.com/nickleus_-_original_guitar_song_200907251723.mp3")
+ self.response.out.write(str(response))
+
+ class DequeueHandler(webapp2.RequestHandler):
+
+ def get(self):
+ # Same as above
+
+ app = webapp2.WSGIApplication([
+ ('/twiml/dequeue', DequeueHandler),
+ ('/twiml/enqueue', EnqueueHandler),
+ ('/twiml/wait', WaitHandler),
+ ], debug=True)
You can also take advantage of similar information when a call is dequeued
through the ``action`` parameter when enqueuing.
@@ -176,13 +312,8 @@ through the ``action`` parameter when enqueuing.
<Enqueue action="/dequeue-logic">radio-callin-queue</Enqueue>
</Response>
-.. code-block:: python
-
- class DequeueLogic(webapp2.RequestHandler):
- def post(self):
- res = self.request.get('QueueResult')
- if res == 'bridged':
- # save to db, ping analytics, whatever you want!
+Twilio will fetch the ``action`` url and execute the TwiML received on the
+caller's end before he or she is bridged to the other call.
Handling Long Queue Times
@@ -257,9 +388,7 @@ dequeue that member.
for queue in client.queues.list():
for member in queue.queue_members.list():
queue_members.dequeue(message_url, member.sid)
-
-As a bonus, try allowing the callers being dequeued to record a message for the
-DJs to listen to at the beginning of the next show.
+
Finally, we can delete the queue using a REST API call.
@@ -267,6 +396,15 @@ Finally, we can delete the queue using a REST API call.
my_queue.delete()
+Advanced Features
+------------------
+
+That is the end of the content for this tutorial. If you still have some time,
+try implementing some of these advanced features:
+
+- Allowing the callers being dequeued to record a message for the DJs to listen to at the beginning of the next show.
+- other features
+
.. _Queue: http://www.twilio.com/docs/api/rest/queue
.. _Member: http://www.twilio.com/docs/api/rest/member
.. _find our queue: https://twilio-python.readthedocs.org/en/latest/usage/queues.html
View
4 docs/custom_twiml.rst
@@ -6,7 +6,7 @@ Introduction to TwiML
We've successfully made a phone ring, but how do we actually control call flow?
`TwiML <https://www.twilio.com/docs/api/twiml>`_ is the
answer. TwiML is a set of instructions you can use to tell Twilio what to do
-when you receive an incoming call or SMS.
+when you receive an incoming call or SMS. TwiML's are formatted in XML and case sensitive.
When someone makes a call or sends an SMS to one of your Twilio numbers, Twilio
will look up the URL associated with that phone number and make a request to
@@ -121,7 +121,7 @@ and paste the following TwiML into your Twimlbin.
This TwiML is invalid. We open the Response and never close it.
-Call your phone number. Do you hear a recorded message that says "We're
+Call your phone number. Do you hear application recorded message that says "We're
sorry, an application error has occurred".
Now let's find out why your application error has occurred. The first place
View
300 docs/dynamic_apps.rst
@@ -13,14 +13,14 @@ SDK running locally on your computer.
Your first web application
--------------------------
-The first part of the guide walked you through running a sample application.
-Before continuing, make sure that app is running and you have "Hello World"
+The first part of this guide walks you through running a sample application.
+Before continuing, make sure your "Hello World" app is running and you have "Hello World"
displayed in your browser. If you can't remember how to run the sample app,
refer back to :ref:`setup`.
-Before we can write our web application, we need to understand the Hello World
-example. Let's go through the example line-by-line and how it works. Inside our
+Before we write our dynamic Twilio application, let's first understand the "Hello World"
+example. Let's go through the example line-by-line and see how it works. Inside our
``main.py`` file:
.. literalinclude:: ../main.py
@@ -29,30 +29,29 @@ example. Let's go through the example line-by-line and how it works. Inside our
This line is the first part of our application. We use the `webapp2
-<http://webapp-improved.appspot.com/>`_ Python module to create our web application,
-so we must do an import before we can use it in our code.
+<http://webapp-improved.appspot.com/>`_ Python module to create our web application.
+Before we can use it in our application, we must first import it.
.. literalinclude:: ../main.py
:language: python
:lines: 3-6
-This code handles incoming requests to our application at the specified URL.
Whenever a user makes a request to our application, this is the code that
-will be run. The output of the code gets displayed to the web browser.
+will be run. The output of the code gets displayed to the web browser. We will name
+this block of code "HelloWorld". The name of a block of code is called the `RequestHandler`.
-Here we only define a single method on the class called ``get``. If you
-remember your HTTP verbs from the :ref:`http` section, this method name
-corresponds to an HTTP GET. We'll show later how to handle different HTTP
-verbs, such as POST or DELETE.
+We are also making a request called ``get``, which grabs the requested resource.
+This corresponds to the HTTP GET request. If you'd like to learn more about HTTP,
+the language browsers use to talk to servers, take a look at our :ref:`http` section.
.. literalinclude:: ../main.py
:language: python
:lines: 8-
-Here we actually create our application. In the `webapp2` framework web
-applications are a mapping of URLs to request handler classes. The above
-mapping says "Whenever someone visits the front page of my application
-(the ``/`` url), process that request using the HelloWorld request handler class".
+In this part of our code, we create our application using the `webapp2` framework.
+The web applications is a mapping of the URL we specify with the listed request handler.
+The above mapping says "Whenever someone visits the front page of my application
+(the ``/`` url), process that request using the HelloWorld request handler".
Your first task will be to change the message displayed in your browser. Open
up ``main.py`` in your text editor and change the "Hello World" message on line
@@ -83,12 +82,14 @@ message we respond with to valid TwiML.
], debug=True)
When someone requests the front page of our application, they will now get TwiML
-instead of HTML. However, if you refresh your page, nothing seems to have
+instead of HTML. If you refresh your page, nothing seems to have
changed.
-The problem is that while we're sending back TwiML, the browser still
-thinks we're sending it HTML. To fix this problem we'll include additional
-metadata via an HTTP header to tell the browser we're sending valid TwiML.
+The problem is that while we're sending back TwiML, the browser still thinks we're
+sending it HTML. Since we never tell the browser that we are sending XML, which is
+the format of TwiML, it assumes that we are using HTML. To fix this problem we'll
+include additional metadata via an HTTP header to tell the browser we're sending
+valid TwiML.
.. code-block:: python
:emphasize-lines: 6
@@ -105,7 +106,7 @@ metadata via an HTTP header to tell the browser we're sending valid TwiML.
('/', HelloWorld),
], debug=True)
-When you refresh the page, you should now see the entire TwiML response (and it
+When you refresh the page, you should now see the entire TwiML response, (it
may even be highlighted and formatted).
@@ -145,43 +146,43 @@ explain what the added code is actually doing.
response = twiml.Response()
-Here we create a new Response object. We'll add additional TwiML verbs using
-methods on this object. We also use this object to output our TwiML into a
-string.
+Here we create a new Response object. Every Twilio application must begin with the
+Response TwiML. We'll add additional TwiML verbs and nest them within the Response
+TwiML.
.. code-block:: python
response.say("Hello TwilioCon")
-This methods adds a Say verb to the response. There are similar methods on the
-response object for Play, Gather, Record, and Dial. We've already covered these
-verbs in the previous sections.
+This methods adds a Say verb to the Response object. The other TwiML verbs Play, Gather,
+Record, and Dial may also be used as methods on Response.
.. code-block:: python
self.response.write(str(response))
-Here we turn our response object into a string using Python's built in string
+Here we turn our response code into a string using Python's built in string
function. We then write this string to the response object.
The Weather Channel
-------------------
-So far all our responses look the same. We're just returning static TwiML as we
-did that the last two sessions. Now we're about to show you why building a
-dynamic application is so powerful. Instead of simply reading a message, we'll
-inform the caller of the current weather in his or her zipcode.
+So far all our responses look the same. We're just returning static TwiML with the same
+message. Now let's build a dynamic application that interacts with your inputs. How about a
+"Weather Channel"! Instead of simply reading a message, we'll inform the caller of the
+current weather in his or her zipcode.
.. note::
The zipcode information Twilio passes to our application is the zipcode of
- the caller's phone number, not to be confused with the zipcode of live
- location of the caller themselves.
+ the caller's phone number, not to be confused with the zipcode of the caller's live
+ location.
.. code-block:: python
:emphasize-lines: 2,10,11,14,15
import webapp2
+ // Import data about the weather
from util import current_weather
from twilio import twiml
@@ -203,7 +204,7 @@ inform the caller of the current weather in his or her zipcode.
], debug=True)
-Now visit your page. You'll see the following message.
+When you visit your page. You'll see the following message.
.. code-block:: xml
@@ -214,7 +215,7 @@ Now visit your page. You'll see the following message.
</Response>
-Our city defaults to San Francisco in case we can't find your zipcode or city.
+Right now in our application, our city defaults to San Francisco in case we can't find your zipcode or city.
To test out the greeting, add the ``FromZip`` and ``FromCity`` parameter to your URL.
.. code-block:: bash
@@ -266,17 +267,97 @@ For a complete list, check out `Twilio request parameters
<http://www.twilio.com/docs/api/twiml/twilio_request#synchronous-request-parameters>`_
on the Twilio Docs.
+Handling Server Errors
+--------------------------------------------
+
+Sometimes, errors happen on the web application side of the code.
+
+.. image:: _static/app_error.png
+
+Don't panic if you see this. The stack trace will usually give you
+hints as to what error the application encountered, and where it occurred.
+
+Some errors may also appear on the AppEngine logs. If the errors on the browser
+aren't too informative, try clicking on the "Logs" button on the AppEngine
+Launcher.
+
+.. TODO: maybe we should include a screen capture of where the Logs button is on the AppEngine launcher. I wanna make the
+.. red circles but I probably can't make it the same as what we have on the Initial Setup guide
+
+Deploy your Twilio application
+------------------------------
+
+We're now ready to hook up your brand new application to a Twilio number. To do this,
+we'll need to host your application live on the Internet, so that Twilio can find it!
+
+Open the Google App Engine Launcher application, highlight your application, and hit
+the "Deploy" button. A window will pop up and show you the status of your
+deployment. It should take less than a minute to deploy.
+
+.. image:: _static/deployapp.png
+
+Once it's deployed, take the URL for your application,
+``http://<your-application-name>.appspot.com`` and set it as the voice number
+for your Twilio phone number. Configuring Twilio numbers is covered in more
+detail in :ref:`configure-number`.
+
+.. note::
+
+ Since we have only implemented the GET endpoint, be sure to configure your
+ number to use the GET method instead of the default POST*
+
+Now give it a call. You should hear your custom message. Hooray!
+
Gathering Digits From the Caller
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--------------------------------
Since not everyone's phone number is from the location they currently live,
it may be helpful to add a feature to our app for checking the weather of
-any zipcode. To achieve this, we're going to use a TwiML verb called ``<Gather>``.
+any zipcode. To achieve this, we're going to use a TwiML verb called `<Gather>
+<http://www.twilio.com/docs/api/twiml/gather>`_.
+
+Let's begin by adding a ``<Gather>`` menu:
-Let's update our file to look like this:
+.. code-block:: python
+ :emphasize-lines: 11-14
+
+ import webapp2
+ from util import current_weather
+ from twilio import twiml
+
+ class HelloWorld(webapp2.RequestHandler):
+
+ def get(self):
+ self.response.headers['Content-Type'] = "application/xml"
+ city = self.request.get("FromCity", "San Francisco")
+
+ response = twiml.Response()
+ gather = response.gather(numDigits=1)
+ gather.say("Press one for the weather in " + city)
+ gather.say("Press two to get the weather for another zip code.")
+ self.response.write(str(response))
+
+The TwiML we've generated so far for the menu looks like this:
+
+.. code-block:: xml
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <Response>
+ <Gather numDigits="1">
+ <Say>Press one for the weather</Say>
+ <Say>Press two to get the weather for another zip code.</Say>
+ </Gather>
+ </Response>
+
+We now have a ``<Gather>`` verb which will allow the caller to type in exactly 1 digit
+(because of the attribute ``maxDigits``). Next, we need to hook it up to something that
+can process the input based on which digits were pressed. When we use ``<Gather>``, these
+digits are passed to us in the next callback using the parameter ``Digits``.
+
+Lets add some additional code to be able to handle this callback.
.. code-block:: python
- :emphasize-lines: 12,13,14,17-43,46
+ :emphasize-lines: 12,17-29
import webapp2
from util import current_weather
@@ -304,103 +385,94 @@ Let's update our file to look like this:
response.say("The current weather is " + weather)
response.redirect("/", method="GET")
else:
- gather = response.gather(action="/weather_for_zip", method="POST", numDigits=5)
+ gather = response.gather(numDigits=5)
gather.say("Please enter a 5 digit zip code.")
self.response.write(str(response))
- class GetWeather(webapp2.RequestHandler):
-
- def post(self):
- response = twiml.Response()
-
- zipcode = self.request.get("Digits")
- weather = current_weather(zipcode)
-
- response.say("The current weather is " + weather)
- response.redirect("/", method="GET")
-
- self.response.write(str(response))
-
app = webapp2.WSGIApplication([
('/', HelloWorld),
- ('/weather_for_zip', GetWeather),
], debug=True)
-A few things of note in this example. The code
-
-.. code-block:: python
-
- response.gather(action="/weather_for_zip", method="POST", numDigits=5)
-
-generates the TwiML for
-
-.. code-block:: xml
-
- <?xml version="1.0" encoding="UTF-8"?>
- <Response>
- <Gather method="POST" action="/weather_for_zip" numDigits="5" />
- </Response>
+First, we've specified that the action of the ``<Gather>`` should be an HTTP ``POST``. Next, we
+added some code to our ``webapp2.RequestHandler`` to respond to a ``POST`` request.
+Because our first ``<Gather>`` specifies a ``POST`` method and no ``action``, the default
+``action`` is the current URL (In this case, "/"). So, this code is what will get run
+after the first ``<Gather>``.
-The ``method`` and ``action`` of the ``<Gather>`` verb tell Twilio what to do when the caller
-finishes entering digits. In this example, we use the ``numDigits`` attribute to
-know when the caller is done pressing digits. This works because we know how many
-digits are in a valid zipcode. If we didn't know this, we could use another attribute called
-``finishOnKey``.
+We pull the value ``digit_pressed`` from ``self.request.get("Digits")`` which corresponds to what
+the caller pressed. In the case that the ``digit_pressed`` was ``"1"``, the behavior looks quite
+similar to our earlier example. We then redirect the user back to the beginning to the menu, so they
+can try again.
-When the caller has entered 5 digits, Twilio will do a ``POST`` request to
-``/weather_for_zip`` with the digits pressed passed as the ``Digits`` argument
-through HTTP. We use these digits to lookup the weather, just as we did for the original
-app with the zipcode passed in by Twilio.
+If the caller presses 2, we ask them for 5 more digits. However, we don't yet have the logic to process
+what to do with these 5 more digits, so nothing interesting will happen when they finish entering.
-We've added a second ``webapp2.RequestHandler`` class. We also configure this handler
-to respond to the URL ``/weather_for_zip`` which is what we're POSTing the second
-gather to.
-
-Another new addition is the ``post`` function on the original ``HelloWorld`` handler.
-This code is triggered when an HTTP client sends a ``POST`` to the ``/`` URL instead of a
-``GET``. Because our first ``<Gather>`` specifies a ``POST`` method and no ``action``, the default
-``action`` is the current URL (In this case, "/"). So, this code is what will get run
-after the first ``<Gather>`` is ``POST``-ed.
+.. note::
+ In this example, we use the ``numDigits`` attribute to know when the is done pressing digits.
+ This works because we know we're looking for exactly one digit. If we didn't know this, we could
+ use another attribute called ``finishOnKey``.
-Handling Server Errors
---------------------------------------------
+Let's find out how to read the zipcode.
-Sometimes, errors happen on the web application side of the code.
+.. code-block:: python
+ :emphasize-lines: 27,30-42,46
-.. image:: _static/app_error.png
+ import webapp2
+ from util import current_weather
+ from twilio import twiml
+
+ class HelloWorld(webapp2.RequestHandler):
+
+ def get(self):
+ self.response.headers['Content-Type'] = "application/xml"
+ city = self.request.get("FromCity", "San Francisco")
-Don't panic if you see this. The stack trace will usually give you
-hints as to what error the application encountered, and where it occurred.
+ response = twiml.Response()
+ gather = response.gather(method="POST", numDigits=1)
+ gather.say("Press one for the weather in " + city)
+ gather.say("Press two to get the weather for another zip code.")
+ self.response.write(str(response))
-Some errors may also appear on the AppEngine logs. If the errors on the browser
-aren't too informative, try clicking on the "Logs" button on the AppEngine
-Launcher.
+ def post(self):
+ response = twiml.Response()
-.. TODO: maybe we should include a screen capture of where the Logs button is on the AppEngine launcher. I wanna make the
-.. red circles but I probably can't make it the same as what we have on the Initial Setup guide
+ weather = current_weather(self.request.get("FromZip", "94117"))
-Deploy your Twilio application
-------------------------------
+ digit_pressed = self.request.get("Digits")
+ if digit_pressed == "1":
+ response.say("The current weather is " + weather)
+ response.redirect("/", method="GET")
+ else:
+ gather = response.gather(action="/weather_for_zip", method="POST", numDigits=5)
+ gather.say("Please enter a 5 digit zip code.")
+ self.response.write(str(response))
-We're now ready to hook up your brand new application to a Twilio number. To do this,
-we'll need to host your application live on the Internet, so that Twilio can find it!
+ class GetWeather(webapp2.RequestHandler):
+
+ def post(self):
+ response = twiml.Response()
-Open the Google App Engine Launcher application, highlight your application, and hit
-the "Deploy" button. A window will pop up and show you the status of your
-deployment. It should take less than a minute to deploy.
+ zipcode = self.request.get("Digits")
+ weather = current_weather(zipcode)
-.. image:: _static/deployapp.png
+ response.say("The current weather is " + weather)
+ response.redirect("/", method="GET")
+
+ self.response.write(str(response))
-Once it's deployed, take the URL for your application,
-``http://<your-application-name>.appspot.com`` and set it as the voice number
-for your Twilio phone number. Configuring Twilio numbers is covered in more
-detail in :ref:`configure-number`.
+ app = webapp2.WSGIApplication([
+ ('/', HelloWorld),
+ ('/weather_for_zip', GetWeather),
+ ], debug=True)
-.. note::
+We've added a second ``webapp2.RequestHandler`` class. We also configure this handler
+to respond to the URL ``/weather_for_zip`` and changed the ``<Gather>`` to point to it.
- Since we have only implemented the GET endpoint, be sure to configure your
- number to use the GET method instead of the default POST*
+When the caller has entered 5 digits, Twilio will do a ``POST`` request to
+``/weather_for_zip`` with the digits pressed passed as the ``Digits`` argument.
+We use these digits to lookup the weather, just as we did for the original
+app with the ``FromZipCode`` passed in by Twilio.
-Now give it a call. You should hear your custom message. Hooray!
+Now, deploy your application again, and try it out!
View
48 docs/hello_world.rst
@@ -35,10 +35,38 @@ You can get to the `API Explorer`_ from the botton of your Account Dashboard. Yo
.. image:: _static/api_explorer.png
:class: screenshot
-Hello World: Sending an SMS
+Getting Account Information
^^^^^^^^^^^^^^^^^^^^^^^^^^^
+<<<<<<< HEAD
Head over to the `API Explorer`_ and let's try it out by `sending an SMS message <https://www.twilio.com/user/account/developer-tools/api-explorer#POST/2010-04-01/Accounts/[AccountSid]/SMS/Messages.[format]>`_.
+=======
+Let's start of with a basic request for your account information. Go to your Twilio Account Portal, click on `Dev Tools`, then click on `Accounts` (on the right near the bottom), then click on `View Account`.
+
+Go ahead and click on the `Make Request` button. A response with your Account information should appear at the end of the page.
+
+**Ok, so what did we just do?**
+
+Let's take a look at the key parts of the request we just made:
+
+.. code-block:: bash
+
+ GET /2010-04-01/Accounts/AC000.xml
+
+This command is specially formatted to function on the command line. Lets break that down a bit:
+
+- **GET**: this line tells curl to make a ``GET`` request, meaning that the intent of this call is to retrieve information from the server.
+- **/2010-04-01/Accounts/AC000.xml**: this is the endpoint for retrieving Account data from the Twilio API. Lets break it down further:
+ - **/2010-04-01/** is the version of the API that we want to request. The version of the API we want to talk to is important because we want to make sure that the way we talk to the API doesn't change. If Twilio makes a major change to how to talk to the API the version will change, but the old version will continue to work the same way so that your application doesn't break.
+ - **Accounts/AC000.xml** means that we want to retrieve an Account resource for the account "AC000" and that we want the response in XML format.
+
+Now lets look at the response. The server responded with an XML formatted representation of your account information.
+
+Sending an SMS
+^^^^^^^^^^^^^^
+
+Let's send a text message using the `API Explorer`_. Go to your Twilio `Account Portal`_, click on `Dev Tools`, then click on `SMS Messages`, then on `Send SMS`.
+>>>>>>> ca8d5a1bc8561250878127831b4eb30e6811a985
All the fields required to send an SMS are visible.
@@ -56,8 +84,21 @@ Enter your cell phone number in the `To` field along with a text message `Body`,
Twilio will process the information you have submitted and your phone will receive a text message shortly.
-Hello World: Making a Phone Call
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+**So how was that different from our Accounts information request?**
+
+Lets take a look at the key parts of this request:
+
+.. code-block:: bash
+
+ POST /2010-04-01/Accounts/AC000/SMS/Messages.xml
+
+There are a few key differences to note:
+
+- **POST** tells curl to make a ``POST`` request, meaning that the purpose of this request is to pass data in to the API for the purposes of modifying the ``SMS Messages`` resource.
+- **Parameters**: if you **-d 'From=xxx'*** et al... tell curl what data to pass to the API. You can see each entry you modified in the form is represented here. You'll also notice that each entry contains special characters (ie: ``%2B`` instead of ``+``). This is called `Url Encoding`_ and is required to make sure that special characters are properly transmitted to the API.
+
+Making a Phone Call
+^^^^^^^^^^^^^^^^^^^
Now let's make a phone call using the `API Explorer`_. Click on the Calls link on the left hand sidebar, then on the sublink `"Make call" <https://www.twilio.com/user/account/developer-tools/api-explorer#POST/2010-04-01/Accounts/[AccountSid]/Calls.[format]>`_.
@@ -94,3 +135,4 @@ Additional Information
.. _E.164: http://en.wikipedia.org/wiki/E.164
.. _TwiML: http://www.twilio.com/docs/api/twiml
.. _Twimlet: https://www.twilio.com/labs/twimlets
+.. _Url Encoding: http://en.wikipedia.org/wiki/Percent-encoding
View
18 docs/setup.rst
@@ -127,12 +127,13 @@ browser window.
.. image:: _static/browseapp.png
-Your browser will open and you'll see "Hello World!" on screen. Let's take a
-moment and look at the URL that is loaded in your browser. The URL says
-``http://localhost:8080/``. `localhost` is a special URL that tells the browser
-to make a request to your local computer instead of out to the internet. The
-``:8080`` portion tells the browser to make the request to port 8080. This URL
-is not visible from the internet and, in general, is only visible to you.
+Your browser will open with the text "Hello World!" on your screen. Let's take a
+moment and look at the URL that is loaded in your browser.
+
+The URL says ``http://localhost:8080/``. `localhost` is a special URL that tells
+the browser to make a request to your local computer instead of out to the internet.
+The ``:8080`` portion tells the browser to make the request to port 8080. This URL
+is not visible and accessible from the internet and, in general, is only visible to you.
.. note::
@@ -169,7 +170,7 @@ Deploy your Application
~~~~~~~~~~~~~~~~~~~~~~~
It's now time to share your application with the world. To deploy your application on
-App Engine, you'll need to create an application via your App Engine dashboard
+App Engine, we'll need to create an application via your App Engine dashboard
(which requires a Google account).
Open the `App Engine dashboard <http://appengine.google.com>`_ in a new tab and
@@ -204,7 +205,8 @@ the application name you registered and save the file.
Open the **Google App Engine Launcher**, highlight your application if it is not
already highlighted, and then click the "Deploy" button. The Launcher app will
-upload your code and deploy it.
+upload your code and deploy it. Your application t is now publicly accessible
+through the internet.
.. image:: _static/deployapp.png
Please sign in to comment.
Something went wrong with that request. Please try again.