Tech, travel, music and food ramblings from Tom Maguire

Creating a RESTful, versioned API using Sinatra

I am relatively new to Ruby and recently built my first Sinatra application. The requirement was to create an API which would detail product information, arranged into a number of API feeds, in a number of data formats.

There are a lot of articles on the web about API versioning in a RESTful manor, so I shall not delve into the details regarding this, but I found this article by Peter Williams to be one of the most useful despite being a couple of years old.

For the purpose of this post, I will be working on the basis that the application would need to accept HTTP requests in the following format:

I decided to use the Sinatra framework to implement the API due to it’s simplicity. Sinatra would provide the basis for handling the HTTP requests, but the more interesting part of the implementation became apparent when deciding how to deal with the vendor mime time in the HTTP Accept header.

To implement the versioned API, three Rack middleware plugins were used:

Rack Conneg

(https://github.com/mbklein/rack-conneg)
Rack Conneg (content negotiation) would be used to respond to a request in the requested format. Conneg parses the Accept header and provides a Rails-style respond_to block interface to allow the application to respond accordingly. Conneg uses the Rack::Mime class to map the Accept header to a data format, however when using a custom vendor mime type such as application/vnd.mycompany.myapp-v2+json, it would be necessary to teach the application how to map these to the desired data type.

Rack Replace HTTP Accept

(https://github.com/tomdmaguire/rack-replace-http-accept)
I created the Rack Replace HTTP Accept adapter to cater for the above scenario. The adapter makes it possible to replace the Accept header based on a regular expressions, changing it into a format that Conneg can negotiate.

Below is a skeleton of the source code for the completed application. If anyone has any feedback I’d love to hear.