my current Work Stack

  • iOS Objective-C
  • Ruby
  • Mongo
  • Rails/Sinatra
  • jQuery
  • Capistrano
  • Passenger
  • Apache.Nginx
  • Heroku
  • Nodejs
last edited 02.10.2012

here's all my posts so far

02/10 Using the Facebook SDK in an IOS Static Library
04/11 Managing Development or Sometimes work gets in the way of work
12/21 Git Stash: For when your boss|clients|life priorities change
12/09 Picker Fields in Titanium
11/30 An Update on Raphael JS and Charts
10/08 How to make a Native App Form that doesn't suck with Titanium
09/23 Notification Subscriptions in Gowalla
09/21 Developing an API in Rails
08/26 I was promised Event Driven APIs and hoverboards. Where are my hoverboards?
08/14 A Node.js wrapper for Gowalla
08/09 Phusion Passenger Tweaking: Apache stuck in Sending(W)
06/28 HTML 5 is here and breaking old hacks we should have never done!
06/26 Simple PDFkit example in Rails 3
06/23 Raphael.serialize
06/12 Serializing RaphaelJS
06/11 Rails 3 beta4 destroyed my Tie Fighter
05/21 Rails 3 and Shoulda
05/13 Using yaml to configure default options for Paperclip
05/07 It's OK to not be pretentious
04/23 Snippet #1
04/21 I Need Closure
04/16 The Good and Bad of Github
04/08 Fun with Beards, or at least mine

here's some tweets I made

Developing an API in Rails

At work it's finally time to open our "API" to some real use. The reason I use quotes around API is that our current implementation does almost nothing and is use by no one. But now we need a real API for our mobile apps and some future third parties.

I've written a few APIs in the past but always exclusively for internal use, and while my next one is primarily for us, I know that in the near future we will need to let some intruders into our home.

So I spent all last week planning the API and sifting through existing ones that I admire. I even talked to some API authors about the problems they had faced.

Here's some references I used:

The main problems I heard from existing API authors:

  1. Regret integrating the API into existing controllers, via respond_to
  2. Inability to change API without breaking third party apps
  3. Lack of knowledge/control of third party developer actions
My approach:
  1. At this time it doesn't make sense for me to split an API out to its own app, using Sinatra or node for speed, because we don't have the traffic. However, I took the regrets of others to heart and decided to completely namespace the api, avoiding mixing logic. Yes, some of my controller logic will be duplicated, but I don't care. If I need to split it out, it's easy; very easy.
  2. I considered using versioned APIs. A simple approach in Rails once you are namespaced is simply to namespace versions in your api namespace. But I didn't want to copy code and add namespaces. So I decided to stick to RESTful APIs for public consumption and save anything different for our internal use. That way, I can change the api however I deem fit, without breaking the RESTful portions. Third parties will just have to do more work than us.
  3. This last problem doesn't seem important to me now, but could in the future once there's a pesky consumer. So I developed a tiered access level of API keys. To the typical public consumer, nothing will seem different, but internally they will have an access level of 1, be restricted to certain requests, and have suspicious activity logged. I decided to create a model that feeds to MongoDB where I can just dump suspicious activity and calculate use rates separately.

At this point I've finished the foundation of the API.

Here are the key features:

  • All controllers are namespaced into api.
  • Every request requires API_KEY in header and authenticates its access level. This is handled in the api namespace base controller.
  • Receives and authenticates optional HTTP Basic User Authentication.
  • Controllers inherit from API::BaseController and can optionally call require_api_login (for HTTP Auth) and require_access_level(num) to restrict access.

Now that all that is finished, with 100% test coverage, I can easily add RESTful controllers to expose JSON and XML per model. It's going swimmingly.

blog comments powered by Disqus