The Big Bang Rewrite (Part 2): API First

As I discussed in my previous post, rebuilding Fave was motivated entirely by the desire for better data. The core focus was not rapid front facing development, but almost entirely back end work. In essence, we started with our API.

One of the features Rails boasts as an application framework is that out of the box, it lends itself to API support. Every controller/action that is generated includes responses for XML based requests. I would challenge most applications to try and publicize an API using the default Rails setup. It’s likely not even close to the end result you’d expect. But that’s OK - no application framework should satisfy that expectation.

At first, our API, was script/console. But, of course, that only got us so far. With our new data model, objects that used to be represented as one were now two three or four different objects. We had normalized our data - aware of the penalties and overhead that would haunt us along the way.

As a result of this normalization, we make heavy use of virtual attributes. It had to be possible to create a Business with one HTTP POST. Phone numbers on businesses, for example, work like so:

class Business < ActiveRecord::Base
  attr_writer :phone_numbers_attributes # [{ :area_code => 312, :exchange => 123, :suffix => 3333 }, ...]
  
  before_validation :set_phone_numbers_from_virtual_attribute
  
  private
    
    def set_phone_numbers_from_virtual_attribute
      @phone_numbers_attributes.each do |phone_number_attributes|
        self.phone_numbers << PhoneNumber.new(phone_number_attributes)
      end if @phone_numbers_attributes
    end
end

In some places take advantage of accepts_nested_attributes_for, however, we found it wouldn’t play nicely with polymorphic associations and were uncomfortable with unknowns it introduced. We’ve found it’s best to write it yourself first, then find abstractions and helpers on a need by need basis.

The controllers, all the meanwhile, have remained “skinny” in spite of complexity. We’ve rigorously moved logic down into the model layer so that the various security components would be the only core responsibility for the controllers. I will go into detail with our approach to security in the next post.

We needed to get data into the application as quickly as possible. As a result, we spent time on an application to simply wrap up the HTTP side of things. It enabled us to create a hash on one end that represented the structure we desired, make the post to the server, and end up with a usable object on the other end. In some ways it is a lot like ActiveResource, and in fact we made enormous progress simply using ActiveResource. But again, our needs grew.

For the longest time, the views of the new site were simply a wrapper to the API. The majority of the teams effort was building the API and other scripts/applications that consumed it. This made for quite a refreshing approach to views, which I’ll discuss in more detail in a later post. The API had forced us to think about what data inputs and outputs were core to the application. It satisfied all the application’s needs first. We no longer had to include messy scripts into our application that relied on directly interfacing with our models to import data. Everything consumed the API. Even the views simply consumed that core data.

All things considered, the API first approach is not one I would recommend to everyone. At Fave, our data is completely core to our business and as a result it seemed appropriate and has paid us in dividends. A site like Piggy Back has far simpler data structures with the user interface demanding much more focus. In this case an “API first” approach would likely be the wrong choice. Although even there I will note that through the process of making the interface more accessible, for example from an iPhone or mobile device, I was forced to clean up my controller and think harder about what data they should and should not be passing in and out. It’s an exercise that every developer should practice and one that has become our regiment at Fave.

Go back to part one or read part three.

Thanks for reading! I'm Avand.

I’ve been working on the web for over a decade and am passionate about building great products.

I devote most of my time to building Lopery, a free budgeting that helps people spend with confidence, recover from the unexpected, and achieve financial independence. I used simple (but time consuming) budgeting principles to buy my first home. Now, I'm codifying (pun intended) those same principles into an easy to use app that helps people achieve their financial goals.

My last job was with Airbnb, where I focused on internal products that helped teams measure the quality of the software they were building. I also built internal tools for employees to stay more connected, especially after the COVID-19 pandemic. Before that, I was lead engineer at Mystery Science, the #1 way in which science is now taught in U.S. elementary school classroms. For a while, I also taught with General Assembly, teaching aspiring developers the basics of front-end web development.

I was born in Boston, grew up in Salt Lake City, and spent many years living in Chicago. In 2013, I came out West to San Francisco, which I called home for almost a decade. Now, I’m based out Mariposa, in the foothills of the Sierras.

I enjoy the great outdoors and absolutely love music and dance. Cars have been an lifelong obsession of mine. I’m the proud owner of a 2002 E-250 Sportsmobile van, and he and I have enjoyed many trips to beautiful and remote parts of the Pacific North West spreading good vibes. I also have a very soft spot for magic (slight of hand, in particular). I love the feeling of being inspired and absolutely love inspiring others.

What can I do for you?

Read my other posts or get in touch: