---
title: How to Evaluate Your Rails JSON API for Performance Improvements
teaser: |
  Before adding database indexes, eager loading, and caches,
  spend a few minutes at the whiteboard with your team to rethink
  the high-level requirements for your JSON API.
tags: web,performance,rails
author: Laila Winner
published_on: 2014-02-10
---

Let's say your company's product is a mobile app that gets its data from an
internal <abbr title="JavaScript Object Notation">JSON</abbr> API. The API,
built using Rails, is a few years old. Response objects are large, request
latency is high, and your data indicates mobile users aren’t converting because
of it.

## Review high level requirements

It can be tempting to immediately dig into your code and look for N+1 queries to
refactor. But if you have the time and bandwidth, try to view this as a great
opportunity to take a step back and rethink the high-level requirements for your
<abbr title="JavaScript Object Notation">JSON</abbr> API. Starting with a
conversation about the desired functionality of each endpoint will help keep
your team's efforts focused on delivering no more than is required by the
client, as efficiently as possible.

Grab your team for a whiteboarding session and review your assumptions about the
behavior of each <abbr title="Application Programming Interface">API</abbr>
endpoint:

* How is this endpoint currently being used by the client?
* What information does the client require for display to the user?
* What needs to be done on the server side before sending a response to the client?
* How frequently does the response content change?
* Why does the response content change?

## Look for performance improvement areas

With the big picture in mind, review your Rails code to identify opportunities
for improving performance. In addition to those N+1 queries, keep an eye out for
the following patterns:

### The response object has properties the client doesn’t use

If you're using `#as_json` to serialize your ActiveRecord models, it's possible
your application is returning more than the client needs. To address this,
consider [using ActiveModel
Serializers](https://thoughtbot.com/blog/fast-json-apis-in-rails-with-key-based-caches-and)
instead of `#as_json`.

### The delivery of the response has unnecessary dependencies

Let's say your <abbr title="Application Programming Interface">API</abbr> has an
endpoint the clients uses for reporting analytics events. Your controller might
look something like this:

```ruby
class AnalyticsEventsController < ApiController
  def create
    job = AnalyticsEventJob.new(params[:analytics_event])

    if job.enqueue
      head 201
    else
      head 422
    end
  end
end
```

Something to consider here is whether the client really needs to know if
enqueueing the job is successful. If not, a simple improvement which preserves
the existing interface might look something like this:

```ruby
class AnalyticsEventsController < ApiController
  before_filter :ensure_valid_params, only: [:create]

  def create
    job = AnalyticsEventJob.new(analytics_event_params)
    job.enqueue
    head 201
  end

  private

  def ensure_valid_params
    unless analytics_event_params.valid?
      head 422
    end
  end

  def analytics_event_params
    analytics_event_params ||= AnalyticsParametersObject.new(
      params[:analytics_event]
    )
  end
end
```

With these changes, the server will respond with a 422 only when the request
parameters are invalid.

### Static responses aren't being cached effectively

It's possible your Rails application is handling more requests than necessary.
Data which is requested frequently by the client but changes infrequently -- the
current user, for example -- presents an opportunity for [HTTP
caching](http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html). Think about
using a CDN like [Fastly](http://www.fastly.com) to provide a [caching
layer](http://www.hward.com/scale-rails-with-varnish-http-caching-layer).

### What's next

The next step after implementing optimizations for performance is to measure
performance gains. You can use tools like [JMeter](http://jmeter.apache.org/) or
services like [BlazeMeter](http://blazemeter.com) and
[Blitz.io](http://blitz.io) to perform load tests in your staging environment.

It's good to keep in mind that through the process of evaluating and improving
your Rails application, your team may discover your <abbr title="Application
Programming Interface">API</abbr> is out of date with the needs of the client.
You may also see opportunities to move processes currently handled by your Rails
application (e.g. persisting and reporting on analytics events) into separate
services.

If an <abbr title="Application Programming Interface">API</abbr> redesign is in
order and the idea of non-RESTful routing doesn't make you too uncomfortable,
you can explore the possibility of adding an [orchestration
layer](http://thenextweb.com/dd/2013/12/17/future-api-design-orchestration-layer/#!t53Ly)
to your API.
