RapidSMS Tutorial Part 2

We’ll continue the tutorial by introducing the RapidSMS default app. Then we’ll show how using RapidSMS handlers can handle parsing incoming messages for you.

Default Application

In part 1, we saw the default application doing its work, responding to messages that no other application had handled. It’s a good idea to keep the default application at the end of INSTALLED_APPS so that it can give some response when your application doesn’t recognize a message. Otherwise your users will get no response and won’t know there was a problem. Or worse, the default application will respond to the message before your app sees it, confusing the user.

You can change the response used by the default application by changing DEFAULT_RESPONSE. For example, if you’ve implemented a HELP command in your project, you might change the default response to:

DEFAULT_RESPONSE = "Sorry, %(project_name)s could not \
understand your message.  Send HELP to get a list of \
valid commands."

Of course, you could also just send the help in the default response.

“Handling” a Message

We said the default application would respond if no other application had handled the message, but how does RapidSMS know that an application has “handled” the message?

One way is for an application’s handle method to return True. That tells RapidSMS that the application has handled the message and no other applications need to try to handle it too. On the other hand, if the application returns False, RapidSMS will continue passing the message to applications in its list until one returns True or it runs out of applications.

That’s why the default application should be kept at the end of the INSTALLED_APPS, because we don’t want RapidSMS to call the default application until it has tried every other one, and RapidSMS calls the applications in the order of INSTALLED_APPS.

RapidSMS Handlers

There are a few very common cases for RapidSMS, such as looking for messages starting with a particular word, or messages that match a particular pattern. Instead of writing that code over and over yourself, you can use RapidSMS handlers.

Using handlers has three steps:

  1. Write one or more subclasses of handler classes.
  2. Add “rapidsms.contrib.handlers” to INSTALLED_APPS.
  3. Add the full classnames of each of your new classes to RAPIDSMS_HANDLERS.

By the way, RapidSMS handlers are just implemented as another app, rapidsms.contrib.handlers. Which shows what you can do with a RapidSMS app.

Keyword Handlers

We mentioned earlier that you might want to implement a HELP command for your users. We can do that using a Keyword Handler.

You’ll write a class that subclasses KeywordHandler. Your keyword will be “help” (it’s not case sensitive). If someone sends just “HELP”, we’ll respond with a message telling them how to get more help. If someone sends “HELP something”, we’ll give them more specific help if we can, and otherwise send the same response we would to a bare “HELP”.

Create a file myhandlers.py with the following content:

# myhandlers.py

from rapidsms.contrib.handlers import KeywordHandler

help_text = {
    'aaa': 'Help for aaa',
    'bbb': 'Help for bbb',
    'ccc': 'Help for ccc',
}


class HelpHandler(KeywordHandler):
    keyword = "help"

    def help(self):
        """Invoked if someone just sends `HELP`.  We also call this
        from `handle` if we don't recognize the arguments to HELP.
        """
        self.respond("Allowed commands are AAA, BBB, and CCC. Send "
                     "HELP <command> for more help on a specific command.")

    def handle(self, text):
        """Invoked if someone sends `HELP <any text>`"""
        text = text.strip().lower()
        if text == 'aaa':
            self.respond(help_text['aaa'])
        elif text == 'bbb':
            self.respond(help_text['bbb'])
        elif text == 'ccc':
            self.respond(help_text['ccc'])
        else:
            self.help()

Now, add “rapidsms.contrib.handlers” to INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    "rapidsms.contrib.handlers",
    ...
]

and add your new class to RAPIDSMS_HANDLERS:

RAPIDSMS_HANDLERS = [
    ...
    "myhandlers.HelpHandler",
    ...
]

Now, if you start RapidSMS and send a message “HELP”, you should get this response:

Allowed commands are AAA, BBB, and CCC. Send HELP <command> for more help on a specific command.

and if you send “HELP AAA”, you should get whatever help is available for AAA.

Handlers Must Handle

Warning

When a handler is called for a message, the handler must handle the message itself, because no other handlers or apps will be called. Since this handler matched the message, RapidSMS expects that this handler will take care of the message. If you need more flexibility, you’ll need to write a normal RapidSMS application.

Pattern Handlers

A Pattern Handler is like a keyword handler, but with two differences:

  1. The pattern can match any part of the message, not just the beginning
  2. Groups can be used in the regular expression to help parse the message. Whatever matches the groups is passed to your handler.

Note

Be careful when deciding to use a pattern handler. Your regular expression needs to be flexible enough to cope with any message someone might send that you want your handler to handle.

Here’s an example from the PatternHandler documentation. You can send a message like “5 plus 3” and it will respond “5+3 = 8”. Note that you cannot send “5 + 3” or “5plus3” or “5 plus 3 ”; none of those match this simple regular expression, so this handler won’t be invoked.

Add this code to your myhandlers.py file:

from rapidsms.contrib.handlers import PatternHandler

class SumHandler(PatternHandler):
    pattern = r'^(\d+) plus (\d+)$'

    def handle(self, a, b):
        a, b = int(a), int(b)
        total = a + b

        self.respond(
            "%d+%d = %d" %
            (a, b, total))

>>> SumHandler.test("1 plus 2")
['1+2 = 3']

and add the new class to RAPIDSMS_HANDLERS:

RAPIDSMS_HANDLERS = [
    ...
    "myhandlers.HelpHandler",
    "myhandlers.SumHandler",
    ...
]

Restart your app, and try sending some messages. 1 plus 2 should get a response of 1+2 = 3. 1+2 should get the default response, because it doesn’t match any of the patterns or keywords of your defined handlers, and no other RapidSMS app is going to process the message.

Continue with RapidSMS Tutorial Part 3.

RapidSMS is a free and open-source framework for dynamic data collection, logistics coordination and communication, leveraging basic short message service (SMS) mobile phone technology.

Getting Help

Related Topics

Table Of Contents