hapi-geo-locate — hapi Plugin for Client Geo Location (by Future Studio 🚀)

You know, we’re aficionados of the hapi framework for Node.js and surely rely on multiple plugins and dependencies.

Honestly, we benefit a lot from the great Node.js and especially hapi ecosystem and all its plugins that do one job very well. That’s the reason we’ve decided to finally give back and open source the first piece of our Future Studio platform as a hapi plugin: hapi-geo-locate, a plugin providing geo location based on the request’s IP address.

hapi Series Overview

What Do You Need Geo Location For?

Future Studio is based in Germany and with the start of the University we need to apply appropriate tax rates as part of the billing procedure. Within the EU, each country has its own VAT rate that gets applied to digital services. To be VAT compliant, we need to make sure the correct rate is applied. To do that, we locate the location of the incoming request using the client’s IP address and further ask you to select your country from a list within the frontend.

Because we didn’t find any existing functionality that we could rely on, we implemented a hapi plugin to provide IP geo location by IP address.

Plugin Functionality: Determine Geo Location by IP Address

To determine your location, we use the service ipinfo.io. Precisely, we use a Node.js wrapper for the ipinfo.io API and pass the client’s IP address to determine their location, not the location of our server. Because if you request the API of ipinfo.io without a valid IP address as an argument, you’ll receive your own location in response.

Decorate the Request: request.location

The plugin decorates hapi’s request interface with a location object that contains the location, if determined correctly. In situations where you disable the plugin (see next section „Options“), the location object is undefined.

Options

The current state of the plugin is an initial implementation with a reduced option set. At the time of writing this announcement, there’s just a single option to disable the plugin for every request or on a route level.

In more detail: the plugin is enabled by default and for each incoming request, the location will be determined which takes time and resources. The actual request processing is blocked until the response from ipinfo.io is received to further proceed with all the other steps applied within the route handler. That’s the reason you can disable hapi-geo-locate globally and enable the plugin if needed for individual routes.

Dependencies

As already described, the hapi-geo-locate plugin relies on a Node.js wrapper for the API of ipinfo.io.

That’s the only dependency we use. We could’ve done the request to ipinfo.io ourselves using an HTTP library like wreck, axios or request, but that would require the implementation of additional functionality around the ipinfo.io API. And we don’t want to invent the development wheel again, just for the sake of spending time on the implementation :) The used dependency provides all required functionality and allows us to add more features on top.

Problem: Get the Client IP Address for Proxied Requests

Using hapi, you can access the client’s IP address using the request object: request.info.remoteAddress. While testing the implementation locally for the actual geo locating procedure, everything went fine.

The Future Studio platform leverages nginx as a reverse proxy to pass the requests to the individual application servers. Locally, we don’t rely on nginx and just start the server using node directly.

At this point, we just used the hapi functionality to determine the client IP address within hapi-geo-locate and didn’t think about the pass through nginx. Once we did the deployment, each client IP was just the 127.0.0.1 loopback. What’s wrong?

Each request that went through nginx to the application server (hapi) contains the IP of your server that runs nginx. In our case, nginx and the Future Studio platform are on the same server.

That means, we need to consider forwarded HTTP headers from nginx to fetch the client’s IP address from there. Ultimately, we prefer proxied headers over the IP address provided by hapi:

const ip = request.headers[ 'x-forwarded-for' ] || request.info.remoteAddress;  

For now, hapi-geo-locate only supports the x-forwarded-for header of nginx. The following list of feature ideas contains the plan to support further proxies besides nginx.

Feature Ideas

The initial plugin state does a solid job of locating the client’s location with the help of its IP address. To support various server setups and use cases, there are multiple ideas that should be added.

Ideas

  • support additional proxies (proxied headers) besides nginx
  • allow IP location services other than ipinfo.io
  • allow API credentials for ipinfo.io

While adding features, we’ll surely come up with additional ideas :)

Do You Want to Contribute?

Do you miss a feature or found an error? Please don’t hesitate to create an issue or just go ahead and fork the repository, add your desired functionality and open a pull request. We’re happy about any community contribution.

Thank you!

Questions?

We’re in the hype of publishing our first hapi plugin and may not have the 10,000 feet view as we should have. In case there’s anything unclear or you’ve a question about the plugin, its implementation or anything else: please reach out on Twitter @futurestud_io or leave a comment below.

Make it rock & enjoy coding!

Explore the Library

Find interesting tutorials and solutions for your problems.