freeCodeCamp Project: Request Header Parser Microservice

Before we get started you can view the project requirements here, you can get the code on github.com to follow along here and you can find a live version of this project here.

As with my other projects, we will be following the steps outlined in this previous post to set up our GitHub repository, clone it to our local machine, set up our dependencies, and finally deploy it to the web. I recommend you check it out If you are still getting to grips with the whole server side javascript environment and workflow.


For this JSON API server we will handle two different GET requests.

  1. Requests to the home '/' path which spits out a simple description of what the app does
  2. Requests to our /whoami path which serves up our specified JSON response

The home path request is a very simple, static text response as seen in the code below:

app.get('/', function(req, res) { 
  res.send('<p>Visit <a href="whoami">/whoami</a> to get the IP address, language and operating system for your browser.</p>');
});

The second request is a little bit more interesting, we begin by initializing our result object which gets sent back to the browser as the response:

app.get('/whoami', function(req, res) { 
  var result = {};

We initialize this here so that the object is empty each time the GET request is made.

While the IP address is the easiest item to grab please note that for this to work on a local machine the code looks a little bit different. For now we will just concentrate on the code that will work once we deploy it to the web.

Here is what the code looks like to grab the IP from the header and parse it out into just the part that we want.

result.ipaddress = req.headers['x-forwarded-for'].split(',')[0];

First we grab the x-forwarded-for property from the request headers. This returns a comma separated string that contains several IP addresses. It will be formatted similar to below:

89.123.123.123,::ffff:10.20.30.123,::ffff:127.0.0.1,10.10.10.22,::ffff:182.27.0.1

The first item is the one we want here, so as you can see in the next part of our code, we use the .split() method with a comma as the separator to split this string up into an array of each of these IP addresses. Then as we want the first item in this array, we access it by its index, [0].

Next we get the language header property in an almost identical manner:

result.language = req.headers['accept-language'].split(',')[0];

Again, this at first spits out a comma separated string with the first item the property we actually want.

The last property we will add in our JSON response is the operating system, this one is a little more complex to parse out but nothing too hard:

var ua = req.headers['user-agent'];
ua = ua.substring(ua.indexOf('(') + 1, ua.indexOf(')')); 
result.software = ua;

The first line here grabs the user-agent property from the request header, this returns a string which will appear something similar to this:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36

As you can see, this is a little tricker to parse out, the text that we want, appears within the first set of parenthesis. To get this, we use the .indexOf() method to find the first instance of ‘(‘ and the first instance of ‘)’, then we pass these values into the .substring() method to get our desired substring. As per the .substring() documentation – the first parameter is:

… an integer between 0 and the length of the string, specifying the offset into the string of the first character to include in the returned substring.

Basically, since the new substring will start inclusive of the index we pass to start at, we need to add 1 to this index so it doesn’t include the opening ‘(‘.

Finally, we send our result object back to the browser as you can see in the code below. This also closes our app.get() code block:

  res.send(result);
});

If you have any questions or feedback on my solution please don’t hesitate to contact me.

Leave a Reply

Your email address will not be published. Required fields are marked *