Scheduled call forwarding using Twilio, AWS Lambda & API Gateway

Introduction

I was recently tasked with implementing time based call forwarding at my workplace.  My company has an onsite team that takes calls on a zendesk provided number during business hours and we have a team offshore that would get any incoming calls outside our business hours.  We wanted the ability to automatically route incoming calls to Zendesk between the hours of 5 AM to 5PM and to the third party vendor outside of these hours.  Initially, we were working with 8X8 to use their service but due to the need to route calls and the call quality provided, we switched to Twilio.

Design

We are going to use Twilio as our provider for phone numbers. Any time there is a call to the twilio provided number, we can take action by connecting to a certain URL.  In other words, Twilio provides the ability to call a POST or GET on some URL to manage how we handle calls.  For low volume of the calls initially, we will be using AWS Lambda/API Gateway as it is easily scalable and relatively cheap service. In future, if the call volumes increase beyond a certain point, we can expose an endpoint from within our app to handle the response for call forwarding.

TwiML Bins

For simple call forwarding with no scheduled switch, Twilio provides a nice XML like language called TwiML (Twilio Markup Language).  When we port numbers to Twilio, twilio provides us with the ability to call external URL using TwiML (Twilio Markup Language) or webhooks.twilio_1

If you navigate to Phone numbers and purchase a number, you will be taken to the screen as shown above.  You can setup simple call forwarding at all times by clicking on the + sign next to TwiML dropdown which will take you to the screen below and allow you to configure the call forwarding to number 1-123-456-7890 in my sample case.
twilio2
For more information on the TwiML syntax for the Dial verb, you can navigate to Dial Verb API.  For our requirement to allow call forwarding for specific hours, however, this approach will not work.  TwiML doesn’t allow complex conditional call forwarding.  To allow for that, we need to host our own webhook code online.

AWS Lambda

AWS Lambda is a compute service that allows user to upload code that will be run as a service on AWS infrastructure.  In our case, we want to trigger the execution when we have a call event on any of the twilio numbers.  I am using Node.js for the project because it has a good support community for Lambda on AWS.  What we want to do is check for the time of the day when the call is generated and based on that respond with a different TwiML to forward call.

API Gateway

The API gateway will be used by us to provide REST endpoint for the Twilio webhook.  On any incoming call, Twilio will hit the API Gateway endpoint that will trigger the Lambda function and pass back the XML response to Twilio webhook thus forwarding the call.

Node.js callForwarding.js code

  • Install node.js
  • Create a folder called twilio-code
  • npm init
    

    This will setup the node project with package.json file

  • npm install moment
    

    I have used moment library to compare the hour of the day. AWS uses UTC time so factor that in the code.

  • Create the twilioCallForwarding.js code and test it locally
  • Final step is to zip up the contents of twilio-code folder in a file named twilioCallForwarding.zip

twilioCallForwarding.js code

var moment = require('moment');
var now = moment();

exports.handler = function (event, context) {
// Event will contain the information passed from Twilio to Lambda.
console.log("Event information: "+JSON.stringify(event));

qryObject = parseQuery(event.reqbody);
var numCalled = qryObject['To'];
var openXml = '<?xml version="1.0" encoding="UTF-8"?><Response><Dial timeout="60">';
var closeXml = '</Dial></Response>';

// Check for time and act accordingly
var hour = now.hour();
responseXml = '';

// Remember that AWS uses UTC time and I used PDT time
if ((hour >= 12) && (numCalled == '+19876543210')) {
responseXml = openXml+'+11234567890'+closeXml;
} else if (numCalled == '+19876543210') {
responseXml = openXml+'+12345987600'+closeXml;
}

// Log responseXml for verification
console.log(responseXml);

context.succeed(responseXml);
};

// Twilio call passes parameters as application-x-www-urlencoded that need to be parsed for our use and hence we will use the following method to parse it.
function parseQuery(qstr) {
var query = {};
var a = qstr.substr(0).split('&');
for (var i = 0; i < a.length; i++) {
var b = a[i].split('=');
query[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || '');
}
return query;
}

AWS provides the handler function with two arguments of event and context (additionally you can also have error as an argument) and refer the lambda documentation to refer how we use them.  Event normally stores parameters that were passed as part of the POST request and context will store the state and response value from Lambda function.

Setting up AWS Lambda

Once you login to the AWS management console, navigate to Lambda under compute section.  On clicking the create a new function link, you will be navigated to blueprint page.  In this case, select runtime of ‘Node.js 4.3’ and filter for ‘twilio-simple-blueprint’.

This will take you to the configure triggers page.  We want our trigger to be an HTTP POST call from Twilio and we will be using API Gateway to handle the event trigger.  Configure the service as following figure shows:

trigger

Lastly, we get to the configure function page.  Name your function the same name as the .js file which will be the entry point to the Node.js code and that contains the exports.handler function.  Modify the handler on the config UI to be twilioCallForwarding.handler.  As we are not going to access any other AWS data (RDS, S3, etc) we don’t need to define a VPC for the function.  The final screen after configuration is as follows:

function

Notice that I have used an existing role that I had created previously for another project.  This role has policies defined that allow access to AWS Lambda, Cloudwatch, API gateway and S3 bucket operations.  Upload a zip named twilioCallForwarding.zip which contains the .javascript source files and all necessary node_modules and head onto the next review screen.  Once you review the function, we can proceed to test the function and verify results.

Setting up API gateway

Proceed to Amazon API Gateway service and click on Create API and enter values as below.

api1

This will create an API for us that we need to add methods/endpoints to. Amazon refers to them as resources.  Click on Actions dropdown and create a New Child Resource with name CallForwarding having resource path of callForwarding.  Select the newly created resource and add a new method to it for POST operation.

 

updatedapi

Next, we will setup the POST method to use our Lambda function located in us-west-2 region.  This will take us to a screen with Method execution flow outlined.  Click on the Integration Request and open the Body mapping templates.  Twilio uses form-urlencoded type to send parameters across which include information such as From number, to number, region of call origination, destination of call, state of the call, etc.  Add a mapping template for type ‘application/x-www-form-urlencoded’ and text as shown in the diagram below and click save to save the changes.

api3

Modify the Method Request to be open for everyone so as to allow everyone access to the API without the need for API key.  This will allow Twilio to call our Endpoint from outside the amazon network.

Next, navigate into the Method Response section and add a Response Model to allow for application/xml response as Twilio expects xml response from our service to redirect calls.  Don’t worry about the response headers as they will be set automatically later on.

api4

Lastly, we need to configure the Integration Response section and add Body Mapping Template that will return application/json with following template:

api5

Now navigate back to the method execution screen and click on our resource method. From the Actions dropdown, select Enable CORS and test the API endpoint.

As a final step, we need to set the URL provided by the API gateway in the Twilio webhook section for phone numbers as shown in the diagram below.  Now calling this Twilio number will forward calls depending on the time of the day.

screen-shot-2016-10-17-at-10-48-43-pm

Advertisements

Netflix on Ubuntu

Once I installed Ubuntu on my desktop, I was not able to go back to windows for some weird partition issues.  I am still struggling to find out how to re-install Windows.  However, I tried logging into the Netflix website from Firefox on Linux Ubuntu and got the following error when trying to view a video.

Ubuntu displayed the following error when playing Netflix Video

Ubuntu displayed the following error when playing Netflix Video

Unfortunately, Netflix requires you to have silverlight plugin to view videos and this plugin is still not available for Ubuntu.  I did some websearch and found a solution to the issue.  Hopefully, this will also help others who want to watch Netflix on Ubuntu OS.  This is a nice tool developed by Erich Hoover and you can donate on
http://netflixonlinux.chipin.com/netflix-works-on-ubuntu to thank him for his work.

So, all you need to do to get netflix to work is open a command terminal and type in following:

sudo apt-add-repository ppa:ehoover/compholio
sudo apt-get update
sudo apt-get install netflix-desktop

The above commands will start the installation of the netflix-desktop application.  In case the installation didn’t go through fine, you can delete it using the following command:

sudo apt-get purge netflix-desktop
sudo apt-get autoremove
sudo apt-add-repository --remove ppa:ehoover/compholio
rm -rf .wine-browser/

One issue which caused me to get stuck at the end of the Gecko Wine installer was navigating the GUI menu but the TAB key helps you move and Enter selects the OK option to proceed.  I was able to start watching netflix using this desktop app and by default it starts it in full-screen mode, you can hit F11 to change it to a window.

Python learning: Intermediate level

Python learning: Intermediate level

I was trying to learn Python in the recent times as we are moving to unix based systems and also PIG allows you to create Python User Defined Functions (UDF).  I used CodeAcademy and a Python beginner’s book to learn the basics and wanted to try and use the knowledge to figure out how much do I actually follow.  CheckIO is a good website to do so which has a narrative intertwined with the coding examples.  The caveat is that you have to solve the questions to view other people’s solutions and have to clear any given level to move forward.

Do check out the site though for Python practice 🙂

Removing header from CSV file

I had a 4 GB csv file from which I wanted to remove the header.  I tried using DOS for doing so as I was not able to open the file in any text editor or in Excel.  Within DOS, I tried the following

MORE +1 DATA.csv > output.csv

The above command would create a file output.csv but it would only contain 13000 rows and then just hang.  I tried creating a batch file to accomplish it but again the same problem arised.  Finally, I fired up my Cygwin terminal and used the following command

sed -i 1d DATA.csv

The UNIX command above will basically modify the file in-place and remove the first line as 1d stands for line number where the action will take place (1 in this case) and the action intended (d stands for delete here).  The problem with sed is that even though you only need to remove line 1, the command will parse through the full file.  A similar option to achieve the same in UNIX is :

awk ‘NR>1 {print}’

JavaScript Associative Arrays

Javascript Associative Arrays

Lately, I have been getting my hands dirty with teeny weeny front end programming.  I kept pestering my managers and lately they have started assigning bugs to me so that I can learn more while fixing them.  Today, while at work a weird bug came to our notice.  We were using arrays to store some information and every time the page was accessed in a different manner, the ordering would change.  I turned the pages of my reference book but it was of no help.  Finally, I walked up to my superior’s desk and spoke to him about the issue.  He took a look and after some research figured out “D’Oh this is because you are using Associative Array!!”  My exact response was “What the hell is that??”

So, I went forth as a brave warrior into the darker realms of javascript, seeking the help of my guide in distress GOOGLE!  Jokes apart, below is a summary and explanation of this new kind of animal in the JS zoo 🙂

Arrays

Most of us who begin learning javascript have come across the regular array notations.  Array can be defined in many ways as follows:

var Array = new Array();
Array[0] = "Apple";
Array[1] = "Ball";

You can also define arrays as follows:

var Array1 = ["Lincoln","Ford","Honda"];
var Array2 = [1,2,3,4];
var Array3 = [1,"Apple",'s'];

As you can see above, Arrays can store numbers, strings or combination of both.  An array that stores combination of these data is known as heterogeneous Array.  However, one thing to notice here is that all these arrays store values in the form of integer index.  For example, if I want to access Apple from Array3 above, I will access it using Array3[1].  Basically, In Array3, the integer 1 is stored at index 0, “Apple” is stored at index 1 and ‘s’ is stored at position 2.  These Arrays are integer index based starting with integer 0.

Associative Arrays

Now coming back to the topic at hand.  In simple terms, Associative arrays are arrays where instead of having integer based indices, we use string indices!!  They are very much similar to hashmaps in a sense that they have string keys and values.  A simple example of this kind of Array is below:

var Array1 = new Array();
Array1["Name"] = "Lincoln";
Array1["Model"] = "MKZ";
Array1["Year"] = 2013;

In the above code, you can use a different notation such as Array1.Name = “Lincoln”; and so on. The methods and properties that you would use with regular Array variable is not going to work with Associative arrays. So, if I do Array1.length here, it is going to evaluate to undefined.  Neither will the push(), pop() and sort() going to work on this array.  In the issue that I defined in the beginning, I was using a sort() method with my associative array which never worked and neither threw any error in the code execution leaving me perplexed about the reason for the failing logic.  Also, regular for loop is not going to work here because Array1 has no integer based indices.  You will have to use for – in loop here as follows:

for (var keySet in Array1)
{
console.log("For property "+ keySet+" the value is : "+Array1[i]); //you can also output using Array1.i
}

Basically, keySet in the code above is going to iterate over all the different keys (indices) of Array1.  This approach is very similar to what we do for Objects and their properties.  You can also try practicing this on CodeAcademy website using their scratchpad.

I hope this was helpful information and please leave your comments if you liked the article.