Building an API

Intro

Building an API is different than building a regular HTML application. There are no HTML views to worry about, but instead you should take extra care about response statuses, response format and especially documentation since your application will be used by other developers.

Creating an application

To generate a Rails application with only the elements necessary for an API application, use the --api flag, e.g., rails new my_application --api.

Use the --api flag only if you're sure that your application will be exclusively an API. If you'll have an admin backend, or use the view layer in some capacity, the Rails API mode will not suffice, and it's best to use the standard rails new command.

We write our APIs using the JSON format, more specifically, we use the JSON API standard. This allows those who consume our APIs to know what to expect regarding the document structure, and they can use libraries which enable them to build their clients faster and easier.

Example app

Check out this example API application that uses a combination of gems used for simplifying our APIs.

Gems

We use a few gems that make our lives easier when writing APIs.

Controller responses

json_api_responders simplifies the code in controllers.

Responding with a status 200 (OK) if the object is valid and with 422 (Unprocessable Entity) would usually look like this:

  if resource.valid?
    render json: resource, status: 200
  else
    render error: errors, status: 422
  end

json_api_responders's method respond_with enables you to simplify the code:

  respond_with resource

Data serialization/deserialization

So far we've used the jsonapi-rails, which takes care of serialization/deserialization of Ruby objects into/out of JSON objects, all according to the JSON API standard, so you don't have to think about those details.

Another alternative is fast_jsonapi. Netflix's gem proved it can do serialization faster. You can check out the benchmark specs if you're interested.

Testing & Documentation

rspec * Testing is always important when building software, but doubly so when writing an API since we can use tests to generate documentation.

dox * Generates documentation from the RSpec tests in the API Blueprint format.

Documentation

You can generate documentation from your controller or request specs. It's very important that you cover all the possible cases and return codes, e.g., a valid response, response when there are errors, and any other outcome of the action. Also, document pagination, enumerations, filtering parameters, sorting parameters, and anything else that may be used to refine the results of the API call.

Take special care to document crucial parts of your API, such as authentication and session management.

Generating documentation should be a part of the Continuous Integration process so that you can be sure your documentation is always up-to-date. You can use a service like Apiary to host the documentation.

Versioning

APIs must be versioned from the start. In that way, in case of large changes, clients can still use the older version of the API while adjusting their application to the new API specification. Otherwise, if the API is not versioned, changes to the API would break the client's applications frequently, and the client would have to take a lot of care to track the changes.

Namespace different API versions in the URL, e.g., a new version of api/v1/resource would look like api/v2/resource. Also, make sure that your application code, that is, your controllers, serializers, tests, and documentation are also namespaced.

Pagination

It's often possible that the API call provides a huge number of results—it could be hundreds of thousands of records. That's impractical if the client needs only a small part of the results. That's why we can limit the number of results returned with pagination, which allows the client to choose which part of the results they want to see in the request, for example, results 500-600 out of 10000.

Pagination is required for every index action, and should be described in the documentation with information on which query parameters are used, what the default and max page size is, etc.

HTTP headers and status codes

If the JSON API standard is used, clients have to set the content-type to application/vnd.api+json in their request headers. In other cases, when using the JSON format, application/json will suffice.

Some of the more commonly used HTTP status codes are:

Success codes

Client error codes

Server error codes

There are many more HTTP status codes. You can go here to read the whole specification.