Rails, Devise and APIs

As a newcomer to Rails and having done a fair amount of background reading, it seemed to make sense that I use Devise to secure access to the API that I was creating. However, in the end I gave up, I could not get the authentication to work reliably and I could not stop Devise from sending HTML out in response to a JSON request. I know that better men than I would have fixed the problem but, as I dug into the issues, I got the feeling that I was going to spend more time removing functionality than I would spend writing what I needed from scratch.

Devise does a lot but, to my mind, a lightweight API doesn’t need much. However, there isn’t much out there to tell you what you need to do. While I was digging around, I came across APIs on Rails which gave me the confidence to remove Devise and start again. I started to work through the examples in the book and had problems with a few of them but there is a Github repository where the issues are discussed and solutions posted. It was not the simplest of processes but it was much more transparent than using Devise.

When it came to Chapter 5, entitled “Authenticating Users” I opted to use Json Web Tokens (JWTs) because they can carry information in much the same manner as a cookie which would, I believed, simplify the implementation server-side. Support for JWTs was added to the project via a Ruby Gem which proved to be well documented and easy to use.

In simple terms the approach is this:

  1. When a client starts a session on the server, they provide their credentials and, in return, are provided a JWT which contains information to identify the client.
  2. The client includes the JWT in the authorization header of every HTTP request sent to the server.
  3. The server opens the JWT, checks the content and allows the request to proceed if everything checks out. If it doesn’t check out, an unauthorised (401) error is returned immediately.

Much simpler than struggling with Devise! Once I got my head around it, it was easy enough to implement. If you are interested, you can take a look at the code on Github.

Rails and Devise are very powerful but so much happens under the hood that they are a minefield for new users who are trying to do something a little out of the ordinary.

 

Mountain Weather

One of the many projects that I worked on during my time at CodeClan was a group project to create a website showing all the Munros that would be sunny today, tomorrow and the day after. The idea being that most people would want to avoid bad weather on the hills and would gravitate to sunny weather if they could easily work out which Munros would have a share of the sunshine. For those unfamiliar with the term, a Munro is a mountain in Scotland that is over 3000ft. tall. I’ve attached a screenshot to give you some idea of what I’m talking about.

The implementation uses JavaScript/React/Rails and has gone through many revisions but is now hosted by Heroku and you can find it at this address: http://www.munrobagger.scot.

 

The first version of the website used the OpenWeatherMap API to collect forecasts for the Munros. The API allows forecasts to be retrieved for a specified latitude and longitude which seems ideal because each Munro has a known latitude and longitude. However, analysis revealed that there were only 26 forecasts to cover a grand total of 282 Munros and the forecasts were all for low altitude so unlikely to be of any real value.

The current version of the website uses the UK Met Office API. This API does not allow you to request a forecast by latitude and longitude. Instead, the Met Office use their own location ids to identify the forecasts for around 5000 separate locations within the UK. The first challenge is to find which Met Office locations are closest to the Munros. Thankfully the Met Office API provides a site-list which contains the lat. and long. of each location so it is possible to find which of the 5000 Met Office location relate to which Munro and therefore which location id to use to fetch the Munro’s forecast.

To get the list of sites I used this API call (API key ommitted):
http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/sitelist

Once I had the list of sites, I used the the Haversine formula to calculate the distance between a mountain and a weather site. Here’s a code snippet to do that (I love the way that Javascript handles the Greek characters):

Mountain.prototype.calculateDistanceTo = function( latLng ) {

  // Haversine formula:
  // a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
  // c = 2 ⋅ atan2( √a, √(1−a) )
  // d = R ⋅ c
  // where φ is latitude, λ is longitude, R is earth’s radius
  // note that angles need to be in radians to pass to trig functions!

  function toRadians(x) {
    return x * Math.PI / 180;
  }

  var R = 6371e3; // in metres
  var φ1 = toRadians(this._latLng.lat);
  var φ2 = toRadians(latLng.lat);
  var Δφ = toRadians(latLng.lat - this._latLng.lat);
  var Δλ = toRadians(latLng.lng - this._latLng.lng);

  var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
    Math.cos(φ1) * Math.cos(φ2) *
    Math.sin(Δλ/2) * Math.sin(Δλ/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = R * c;

  return d;
}

When I ran the code I found that the nearest weather site was always right on top of the mountain so there was never any doubt about which location id to use. Exactly what was needed! No other weather service provides this level of coverage for Scottish peaks.

To give an example: Ben Nevis (the highest Munro of them all) has a latitude of 56.796849 and a longitude of -5.003525. Using the site list retrieved from the Met Office and the Haversine formula we find that the nearest location id is 350377.  A five-day forecast for Ben Nevis is retrieved using a request like this (where the API key and forecast type have been omitted): http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/350377

To have access to the API free of charge, utilisation must stay within the fair use limits which are:

  • No more than 5000 data requests per day and
  • No more than 100 data requests per minute

There are 282 forecasts which are updated at most once per hour so 6768 requests would be needed to stay in sync with the Met Office. This would break the fair use limits so we need to reduce the frequency of update and we need the server, rather then the client, to get the forecasts; multiple clients using the same API key would break the fair use limit very quickly. In practice the Rails server updates the forecasts once every two hours and, while updating, requests a new forecast once a second to ensure that it only ever makes 60 requests per minute.

The Met Office API is a little tricky to use when compared with something like OpenWeatherMap but for an application like this you can’t beat it.