These days people expect great experiences when interacting with web apps. Facebook, Twitter, Google, et al have spoiled the average web user with the rich, real time applications that load in a tenth of a second. Modern web users expect
- Forms to not require a full page reload on submission.
- Caching to be utilized at every layer.
- Pages to redraw to reflect any changes in data... in real time.
New business models are emerging where a lot of customer touch time is handled using text messaging. Concierge services like Magic, survey research labs, and credit card fraud departments all rely on SMS for real time, low friction communication with people. Other businesses use voice communication for things like phone menus (press 1 for...), telemarketing, and traditional survey research.
There are some new but maturing technologies out there to help us write software that meets the grandiose expectations of the customer and helps businesses meet their telecommunication needs.
Twilio provides a globally available API on which developers can build complex telecommunication applications. They will give us the ability to program an application that makes phone calls and send messages.
To begin you will need to install meteor using the directions on the Meteor website.
For os x and linux users boils down to a one liner which will download the meteor installation shell script and run it using your default shell.
curl https://install.meteor.com/ | sh
Windows users will need to download the latest installer.
Note: When running a Meteor application locally, it will manage running mongodb for you and there is no reason to have your own instance running for development purposes. If you have your own database you'd like to use, see the directions included in the application repository.
After Meteor is installed, we will create a new application using the meteor command line tool that was installed earlier.
meteor create hello-twilio
At this point your application should look almost identical to this project created with Meteor v1.2.1.
Meteor has its own packages and the index, Atmosphere, is full of bindings for common Node.js libraries (And tons of original content!). To begin sending messages using the node.js Twilio library, we will install the smart package from atmosphere.
meteor add dispatch:twilio
This modifies both
.meteor/packages. Commit these so that anyone who clones your project has the meta data available to know which packages are needed without having to commit the packages to source control.
Define Twilio Settings
dispatch:twiolio is configured by adding keys to a
Since we have no other settings yet, we will create
settings.json with this content:
To load the application with the settings configured in
settings.json you'll need to start Meteor using this new command
meteor run --settings=settings.json
And in order to prevent checking your Twilio secrets into source control, we will also modify the
.gitignore file to prevent it from being committed.
Note: It is not a good idea to track secrets in source control. They should be handled in another fashion because those keys shouldn't be public knowledge.
Create Twilio Client
The keys defined in the settings.json loaded with
--settings are available globally inside server side Meteor application code as an object known as
Meteor.settings. Creating a new Twilio client is as simple as passing those values through to the Twilio library.
Note: By using this pattern rather than just assuming the values are at
TWILIO.TOKEN, the library allows you to create multiple clients in case you want to send messages from different numbers or using multiple Twilio accounts. It costs you a couple of lines of code, but increases the flexibility.
Remote Procedure Call
Meteor is a full stack framework and has both a client and a server component. The mechanism for requesting the server to run trusted code in Meteor is "Meteor Methods". Writing a Meteor method is a straight forward process and consuming one is just as simple.
Note: Trusted Code is code that is known to be untampered with. In browsers, a user can replace any or all of the code in your app. If you want to be sure a certain chunk of logic is performed, the appropriate place to run it is in a trusted environment, which is usually the server.
Sending an SMS is an example of something that should be done with trusted code. You might want to ensure a user is authenticated, that the recipient has authorized your service to send them SMS, or guarantee that a log is created that sending an SMS was attempted by the client.
By following the Meteor Documentation on Methods, implementing the sendSMS method looks like:
try/catch block is used to catch any errors thrown by the Twilio library code.
Record outgoing SMS
While this code works now, it doesn't do much to give the users any feedback. It would be nice to log that the message was sent and record that in the database. To be able to write to the database, we need to request a
collection handle from Meteor by calling new Mongo.Collection at the top of
// omit `var` in order to make this globally accessible to the server. SMS = new Mongo.Collection('sms');
Now we can update the
sendSMS method to write outgoing sms to the database.
Make it do something
Now that we have a trusted mechanism for sending SMS via Twilio, it is time to wire it up to the client.
Just to be a bit more explicit about where all of this code is available, let's move all the client specific code into
client/. If you're using bash this can be done with
mkdir client && mv hello-twilio.* client/. The project should now look roughly like this.
sendSMS template. The click event will cause a
Meteor Method to be fired on the server which will request Twilio to send an SMS on our behalf.
Getting Incoming Messages from Twilio
There are several distinct steps to this process.
First we need a version of
twilioClient.client.messages.list that has access to the Meteor context inside of the callback. In particular, Meteor async methods are run within a fiber, so we need to ensure that this callback has access to one. This is where Meteor.wrapAsync comes in handy.
Next, we need a mechanism that can update the messages in our local database from Twilio. This is the
updateMessages function below. The trick here is to ignore any messages we've seen before so we don't end up with a boat load of duplicate data.
Lastly we need to call
updateMessages every 60 seconds so we use Meteor.setInterval.
Displaying a log of SMS
Now that we have a copy of all the incoming and outgoing messages in our database, it would be nice to display them the user so that they know what has been said before in order to make sense when conversing with a message recipient.
To accomplish this, we want to use HTML to display a line item for every message in the database. With the help of Spacebars, we can knock this out in short order by defining a new template
smsLog and including it in the
body tag. Using the
each block helper, we can loop over a set of SMS and output an
li tag for each one.
In order to power the new
smsLog template, we need to indicate which messages to show and a way to determine if a message was sent by a user or if it was received by the system. In our case we want to show all the messages in reverse chronological order and to read from the
type field to determine who the sender of the message was.
Note: You'll notice that the SMS data is available on the client magically. In Meteor, applications begin with a package called
autopublish which syncs all the data on the server with the client. See the section on data and security in the Meteor documentation for more information.
SMS client in less than 150 lines ?!?!?!
If you go tally them up, you'll notice that this entire application was written in under 150 lines of code. This is possible because Meteor provides a lot of plumbing and makes a lot of assumptions for the developer. It is also significant that Twilio's client library mostly stayed out of our way and let us get to the business logic specific to our use case rather than spend forever dealing with sending SMS.
The tools available to today's developers are growing in power but expect those who use them to grok much about how they work in order to be utilized properly.
What will you build next?