How Flxt.it Uses Twilio To Make Sure You Never Miss A Good Movie
Time to read: 35 minutes
Ever been out at dinner and had someone mention a movie you have to watch (Like, Gattaca.), and then went home and promptly forgot the name? Flxt.it wants to make sure a good movie never goes unseen. Simply text the name of the movie to Flxt.it’s phone number and it’ll be added to your Netflix queue. This is a guest post by Flxt.it’s creator, John Clayton, on how he used Twilio to develop Flxt.it.
The other morning another tweet popped up on my desktop…my entry won!
And now…I’m proud to introduce Flxt.it — a simple tool to manage your Netflix queue.
The Idea
How many times have you been away from a computer and thought of a movie you don’t want to miss? This is where Flxt.it comes in — if you can send a text message, you can add movies to your Netflix queue. There are existing applications to accomplish this, but sending a text message is faster, and you don’t need a smart phone.
The Implementation
When you sign up for Flxt.it, your Netflix account is linked to your cell phone, and you’re given a phone number to send movie titles to. This number is provided by Twilio and it’s where the magic begins.
When Twilio receives a text message, it sends the information on to the web application, which is running ASP.NET MVC 3. In Flxt.it there is a single endpoint that receives the message, looks up your Netflix account information, takes care of business, and responds with a text message to let you know the movie was added to your queue.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
public
class
Message
{
public
string
AccountSid {
get
;
set
; }
public
string
Body {
get
;
set
; }
public
string
From {
get
;
set
; }
public
string
FromCity {
get
;
set
; }
public
string
FromCountry {
get
;
set
; }
public
string
FromState {
get
;
set
; }
public
string
FromZip {
get
;
set
; }
public
string
SmsSid {
get
;
set
; }
public
string
To {
get
;
set
; }
public
string
ToCity {
get
;
set
; }
public
string
ToCountry {
get
;
set
; }
public
string
ToState {
get
;
set
; }
public
string
ToZip {
get
;
set
; }
}
[ValidateTwilioSignature(
"YourTwilioAuthToken"
)]
public
class
SmsController : TwilioController
{
[HttpPost]
public
ActionResult Search(Message message)
{
var user = db.Single<User>(u => u.PhoneHash == message.From.NormalizeAndHash());
var movie = netflix.Search(message.Body, user.NetflixApiToken);
if
(netflix.AddToQueue(movie, user.NetflixApiToken))
return
Sms(
"{0} has been added to your queue!"
, movie.Title);
return
Sms(
"Unable to add to your queue."
);
}
protected
override
void
OnException(ExceptionContext filterContext)
{
Log.Write(filterContext.Exception);
filterContext.Result = Sms(
"Whoops! Something went wrong. Please try again later."
);
filterContext.ExceptionHandled =
true
;
}
}
|
MVC’s model binding turns all the parameters Twilio sends into an easy to use class. To respond to the incoming message there are two options — TwiML or REST. The former is the only option if you want to do more than one action, like send multiple SMS messages and redirect to another TwiML document. The later is the easier option when you just want to send a response — set your response’s content type to text/plain and Twilio will send the response body to the sender as an SMS message!
This was the approach used by Flxt.it. A custom SmsResult sets the content type and makes sure that the message doesn’t exceed 160 characters. If you don’t want to send a reply message simply send an empty response.
It’s also important to handle any errors properly so that Twilio always gets a valid response from your application. MVC makes this crazy easy without needing to wrap your entire action in a try/catch. By either overloading the OnException method or providing a custom filter to the action or controller you can return an SmsResult no matter what happens during the action.
Security & Privacy
We are all concerned about privacy, so handling phone numbers should not be taken lightly. Even in a simple application like this I want to take every precaution to keep users’ phone numbers safe.
The first, and most effective, precaution is Flxt.it does not store the full phone numbers. Because Flxt.it will always be responding to incoming messages, it will store a hash of the phone number and the last four digits and still be able to link your Netflix account to your incoming movie request.
The second way to protect the Twilio endpoint is to ensure that Flxt.it will respond to requests from Twilio and nobody else. In every request, Twilio will sign the request using your secret authentication token and send it in a HTTP header. To validate it you perform the same operation and if the request is valid you will get the exact same value.
The following is an example of how you can create an action filter in MVC to easily validate an action or every action in a controller. It’s based on John Sheehan’s most excellent presentation at mvcConf last week.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
public
class
ValidateTwilioSignatureAttribute : ActionFilterAttribute
{
public
ValidateTwilioSignatureAttribute(
string
authToken)
{
authToken.ThrowIfNullOrEmpty(
"authToken"
);
AuthToken = authToken;
}
public
string
AuthToken {
get
;
private
set
; }
public
override
void
OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext.Request;
var fullUrl = String.Format(
"http:///">http://{0}{1}"
, request.Url.Host, request.Url.PathAndQuery);
var valueToHash =
new
StringBuilder(fullUrl);
if
(request.HttpMethod ==
"POST"
)
{
var sortedParams = request.Form.AllKeys.OrderBy(p => p).ToList();
foreach
(var param
in
sortedParams)
{
valueToHash.Append(param);
valueToHash.Append(request.Form[param]);
}
}
var sha1 =
new
HMACSHA1(Encoding.UTF8.GetBytes(AuthToken));
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(valueToHash.ToString()));
var encodedHash = Convert.ToBase64String(hash);
var twilioSignature = request.Headers[
"X-Twilio-Signature"
];
if
(encodedHash != twilioSignature)
filterContext.Result =
new
HttpForbiddenResult();
}
}
|
One thing to note here is that when you are in a load-balanced environment like AppHarbor the web server your request is being served by is likely not the exact address that Twilio calls from the outside. Since it is part of the signature we need to be sure to use the host header value and not the raw URL as seen by ASP.NET.
Couldn’t Be Easier
In Flxt.it I’m barely scratching the surface of Twilio’s capabilities. In addition to sending and receiving SMS messages, they have an incredibly powerful platform for making and receiving phone calls. Best of all it’s available on a pay as you go basis — no contracts! You no longer need to be a Twitter-sized company to be able to add phone and SMS capabilities to your application.
Go ahead and try it out for yourself — you get $30 worth of credits just for signing up!
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.