Exclude regex based paths in Spring boot

Question

I have a controller with the following GetMapping

@GetMapping(value = "/dawson/v1/{dataType}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity respondWithData(@PathVariable String dataType, @RequestParam(name = "minDate") String min_date, @RequestParam(name = "maxDate") String max_date, @RequestParam(USERID) String user_id, @RequestHeader(value = "Authorization") String authorizationHeader) {

where dataType can be one of either String, Map, Object or Calendar.  I created another GetMapping as follows in a different class

@GetMapping(value = "/dawson/v1/signInReq")
public ResponseEntity mySignInRequest(@RequestBody Map paramMap, HttpServletRequest request, HttpServletResponse response) {

However, when I try to access the /dawson/v1/signInReq, I instead get a match with respondWithData method and not the mySignInRequest.  So, Is there a way to exclude signInReq as a match for {dataType}?

Answer

It seems like there is a way to exclude certain mapped paths in your mapping using regex.

@GetMapping(value = "/dawson/v1/{dataType:^.*(?!signInReq)}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity respondWithData(@PathVariable String dataType, @RequestParam(name = "minDate") String min_date, @RequestParam(name = "maxDate") String max_date, @RequestParam(USERID) String user_id, @RequestHeader(value = "Authorization") String authorizationHeader) {

As shown above, by using regular expression, we can filter out signInReq from the mapping of acceptable dataTypes.

Advertisements

Blessed with a daughter

The last post I was able to write was January 20, 2017.  I am starting again after almost 1.5 years as December 2016, I was blessed with the most precious baby girl.  I have had no time to write a blog since then as all my free time is occupied by my lovely doll.  In the past year, I moved from always working for startups (Nomis Solutions followed by Lyra Health) to working for a large organization like Intuit Inc.

Leaving Lyra Health was a really big decision for me and I am so grateful to the team at Lyra Health for making me feel this valued.  It was immense pleasure working in behavioral health space and get guidance from Jenny Gonsalves and Albert Baranchuk.  I am sure that under David’s leadership, Lyra is going to do some awesome work and is a company I am glad that I contributed to.  I learnt a lot about working with AWS, Twilio APIs, managing projects from start to finish and managing third party vendors for email communication (SalesForce and SparkPost) and Okta for authentication.

Lastly, I am now a certified AWS Solution Architect – professional and cloud practitioner.  Two certifications that I find valuable.  At Intuit, I have been focused on working with Kubernetes deployment, managing AWS clusters and DevOps related tasks.

Sending SMS with Twilio using node.js

This blog post is more of a tutorial for myself.  Prior to trying this out, from the online twilio account buy a phone number that allows SMS communication.

The first step is to simple install twilio sdk for node using following command in the directory where you want to send messages from.

mkdir ~/twilio-code
cd ~/twilio-code
npm install twilio

Create a file under the directory twilio-code and name it sendTest.js


var accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
var authToken = '0XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';

//require the Twilio module and create a REST client
var client = require('twilio')(accountSid, authToken);

client.messages.create({
to: "+11234567890",
from: "+19876543210",
body: "How you doin?",
}, function(err, message) {
console.log(message.sid);
});

Now running node sendText.js command from the command line, you will be able to send the text message easily.  Each text message sent using twilio is charged some amount so be careful with your testing or use the test SID and AuthToken that Twilio provides.

 

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

Windows USB/External HDD on OSX

It is such a pain to open any external hard drive or USB stick that has been written and formatted on a windows machine when trying to open it up on a macbook.  I was trying to access photos on my external hard disk that had been originally formatted using a Windows 7 OS (thus NTFS file system) and I could only read the files on my macbook but make no edits to them.  I read online that there are some paid tools that allow you to access the files on such drives but I try not to pay for tools that I’ve never heard of.  The other option is to re-format the drive on mac but that causes wiping out all data on the drive.

I came across the following steps that allow you to enable Mac OSX 10 to access files on such external hard drive without formatting it or losing any data.  Note: You need to have sudo rights (or be the administrator with root privilege) to perform the operation.

Run the following steps on mac OS terminal (can be started by pressing Command + space and typing terminal) :

$> sudo vi /etc/fstab

In the vi editor, add the following line:
LABEL=WESTERNDIGITAL none ntfs rw,auto,nobrowse

and then type :wq! to exit the vi editor window. On the terminal run:

$> diskutil unmount WESTERNDIGITAL
$> diskutil mount WESTERNDIGITAL

Note:  Replace WESTERNDIGITAL with the name of your drive in all lines above with the drive name as showing up in finder window.  If your drive name contains spaces, use quotes around the name e.g. “WD DRIVE”.  You can also find the name by running :

$> ls /Volumes/

There will be a Macintosh HD and the other will be your USB/External HDD. It might happen that the finder window will not show your drive once you have made the change mentioned above.  To open the drive with RW mode, run following in your terminal window:

$> open /Volumes/WESTERNDIGITAL

White Water Rafting

With sunny summer days around in the month of June, a friend of mine decided to arrange for white water rafting trip.  Having never done it before, it seemed like a really swell idea and I agreed to do it on a Saturday morning.

We drove to Lotus camp near Placerville, CA early in the morning from San Jose.  The company that provided us services for the day was Action Whitewater Adventures.  Our guide was a cheerful Costa Rican named Marcello.  We had opted for a full day river and that meant rowing for nearly 3 hours at a stretch.  The water was really pleasant and the second part of the river contains some really cool Level 3 rapids.  We had fun the whole day with shoting and screaming and made some friends for the duration of the day who were on another raft but with the same company.  Groupon keeps giving deals for rafting and do keep an eye out for it as a full day of rafting, also including lunch, was about 90$.

At the end of the trip, Action Whitewater Adventures allows you to purchase pictures from the rapids for around 50$ for 1 rapid, 75 for 2 rapids and 100$ if you want to purchase all pictures.  There are some independent photographers around who charge a bit less than AWA, one example being Sierra Nevada Pictures.  Make sure to apply tons of waterproof sunscreen when you go because you will be mostly under the UV rays of sun and I had a severe case of sunburn on my knees.

We were super sore from the whole day activity and went over to Punjabi Dhaba, an authentic punjabi dinner place near I-80 of Sacramento.  We munched on the dinner buffet before heading back home and directly to bed to sleep.

 

Lastpass Password Manager

I was recently introduced to this Chrome browser extension called Lastpass.  This is a really handy extension that allows you to store passwords for multiple sites.  The advantage is that I have one single 20 character mixed password that I use to log into Lastpass and then using lastpass, I can generate passwords that are 50-100 characters and I don’t have to remember them.  It provides the following benefits:

  1. Extra security:  I no longer have to use the same password for multiple sites so that I remember it.
  2. Autochanging password: One of the nice features is that lastpass reminds you to change password every set duration.  This is useful for banking or applications that contain sensitive data
  3. Sharing passwords: I can share passwords with other users within my team without giving out my actual password and I can then change the password

I just love this service and you should also give it a try.  They have a free version that is really good and once you start using it, you can upgrade to the premium service that is 12$ a year.