The Basics of Building an API in Ruby on Rails

Launch Academy

By Launch Academy

February 1, 2022

What exactly is an API?

If you’ve done any web development, or spent any time in tech circles, odds are pretty good you’ve heard the term API before. An API is an “application program interface”, which basically means a computer program that allows other programs to communicate with it. In our case, our program will be a web application, and we want to make it easy for other web apps to connect to it.

For example, let’s say I want to build a simple web app that searches Twitter for tweets that contain certain keywords. I can use Twitter’s search API to do just that by sending a request for data to their servers and then manipulating or displaying that data on my app. There are tons of APIs out there that make their data available to developers for things like movie times, restaurant reviews, social media, any pretty much everything else. Access to an API is often free of charge, although typically limited to the number of requests you can make in a given time period.

But what is that process like from the other side? Let’s say you have some data that you want to make available to other developers so they can take advantage of it in their apps. Or maybe you have a web app that you want to make available on mobile. Both of these situations are ideal for building your very own API.

Following Conventions

Ok, so you’ve decided to build an API, but you’re not sure where to start. First things first, we have some decisions to make about how our API will work.

Formatting Our Data

When a Rails app renders data to the browser, it generally formats that data as HTML, which is the basic language of the Web. HTML isn’t the only format available to us though, and in our case it’s probably not the best choice. HTML is great at laying out data in a way that is easy to read for humans. You would generally use HTML when you want to build a web page that a user will be visiting, because things are structured the way a user would expect to see them.

Unfortunately, humans and computers don’t read things in the same way, so we probably don’t want to feed our applications data that’s written for people. If we want our data to be more readable to our apps, we need it to be formatted in a way that’s easy for computers to use. If you’ve done some work in Ruby already, you might have some ideas of how we would want our data to be organized: arrays and hashes.

Luckily for us there’s a format that is very similar to Ruby’s data structures called JSON (JavaScript Object Notation) that Ruby is already able to parse for us with a built in library. JSON is a widely used data format and most common web languages can deal with it with relative ease, so we’ll be using JSON for our API. There is even a handy set of conventions (which we all love as Rails developers, right?) that can help us make sure our JSON is formatted in a way that other developers will be expecting to receive it.

Getting Plenty of REST

You may have heard the terms REST or RESTful at some point in your development career so far. What exactly does REST mean? REST (Representational State Transfer), in the context of database-backed web applications, is the mapping of HTTP verbs to database CRUD operations. There are a lot of principles that guide truly RESTful development, so we will just talk about what it means on the surface for us as Rails developers.

If we think back to the C of the MVC pattern, our controllers, you might already be able to name the seven RESTful actions that Rails handles. They are Index, Show, New, Create, Edit, Update, and Destroy. Each of these actions also corresponds to one of the CRUD operations: Create, Read, Update, and Delete, and, are activated by one of the HTTP request methods: GET, POST, PUT, and DELETE.

The basic functions of these actions should be pretty apparent. Some are used simply to retrieve information from the database (GET), others create records in our database (POST), some modify records (PUT or PATCH), and other delete records (DELETE). Our API will follow these guidelines as well, which will standardize the way we are using the HTTP protocol to interact with our data.

| HTTP Verb | Controller Action | CRUD Operation | | --- | --- | --- | | GET | Show, Index, New, Edit | Read | | POST | Create | Create | | PUT/PATCH | Update | Update | | DELETE | Destroy | Delete |

You may notice that New and Edit are in the GET/Read column and think that they got lost on their way to Create and Update. However, the New and Edit actions are actually used to generate a form page for the user to enter data, and don’t actually add anything to our database yet, so they get along perfectly well with the other GET actions.

What Tools Should I Use?

We’ve talked about what formats and conventions we are going to adhere to with our API, so now let’s get into the software we’ll use to build it.

When it comes to rendering JSON in Rails, there are a few options available. The simplest option is to simply use Ruby’s included JSON library to convert your data right in your controller. This is the simplest option, but it also offers the least flexibility. You really don’t have much power to manipulate the way you present your data, and if we want to follow the proper formatting conventions outlined in the JSON API standard, the built in JSON library just isn’t going to cut it.

Next in line is Jbuilder, which is included into Rails by default by the Rails core team. While Jbuilder offers more flexibility in terms of manipulating our JSON, it’s still not an ideal solution. One reason for this is the way it forms JSON from ActiveRecord objects. If we look at this example from the Jbuilder GitHub page:

@people = People.all
json.array! @people, :id, :name # => [ { "id": 1, "name": "David" }, { "id": 2, "name": "Jamie" } ]

We can see the problem with the JSON we get back. If we talk about this in terms of Ruby data structures, we see two hashes within an array. Inside each of these hashes, we can see two attributes for each instance of the People class. However, let’s say we’re on the receiving end of this JSON. All we would see if a series of hashes with information without any kind of identifier as to what kind of objects we’re looking at. You can imagine a scenario where a JSON response might include several types of objects, and without a top level key, it’s going to be far more difficult for a developer to work with the data.

This brings us to what I consider our best option for rendering JSON in a Rails API, ActiveModel::Serializers. ActiveModel::Serializers offers us several advantages over the default Jbuilder. For one thing, it is considerably faster, working as much as 10x faster than Jbuilder depending on what kind of JSON you are building. For another thing, it solves our issue of missing top level keys as you can see in the example below:


{
  "people":[
    {
      "id":1,
      "name":"David"
    },
    {
      "id":2,
      "name":"Jamie"
    }

  ]
}

Our data is now clearly organized by model name for easy manipulation by the application that receives it.

Let’s Get to Building

When building a Rails API, there are several differences from developing a regular Rails web app that you’ll need to keep in mind. Conveniently enough, the first thing I would recommend doing differently is the very first command you enter in building your app. Rather than using ‘rails new APP_NAME’ to generate the skeleton of your new app, I would suggest using the rails_api gem to build a more lightweight app that strips out the parts of Rails we won’t need.

$ gem install rails-api
$ rails-api new APP_NAME

The rails-api gem will generate the same Rails structure you’re already familiar with, minus some of the parts we won’t be using, such as the assets pipeline and the views directory, since our API won’t be rendering any views.

Controllers

Let’s look at some of the differences in our controllers next. Let’s imagine a PostsController for a blog app. What might our Index and Show actions look like in a regular app?

def index

  @posts = Post.all

end

def show

  @post = Post.find(params[:id])

end

While we don’t explicitly tell Rails what view to render for these actions, it knows by default to looks in ‘app/views/posts/index.html.erb’ and ‘app/views/posts/show.html.erb’ respectively, so we can just set out instance variables. Now what would these same actions look like for an API controller?

def index

  render json: Post.all

end

def show

  render json: Post.find(params[:id])

end

As you can see, here we have to be a bit more explicit with Rails, since its default behavior is to render a view, we want to instead tell it to render some JSON, and then specify what objects we want it to build that JSON from.

Let’s take a look at some more controller actions.

def create

  @post = Post.new(post_params)

  if @post.save

    render json: @post, status: :created, location: api_post_path(@post)

  else

    render json: @post.errors, status: :unprocessable_entity

  end

end


def update

  @post = Post.find(params[:id])

  if @post.update(post_params)

    head :no_content

  else

    render json: @post.errors, status: :unprocessable_entity

   end

end


def destroy

  @post = Post.find(params[:id])

  if @post.destroy

    head :no_content

  else

    render json: @post.errors, status: :unprocessable_entity

  end

end


private
def post_params

  #...

end

 

You may start noticing some more differences here. For one thing, we don’t have a new or an edit action, because like we’ve mentioned, our API isn’t rendering views. That means that users aren’t filling out forms to create data, but instead, requests are being sent directly to the create and update actions. You’ll also notice some extra information in some of our render statements. These statuses and locations we are setting are conventions according to the JSON API standards, and they make it explicitly clear to other apps what the result of each action is. These correspond to the HTTP response codes to declare successes and failures.

Serializers

Remember that ActiveModel::Serializers gem we decided we were going to use a few hundred words ago? Let’s implement that now by building a serializer for our data. First let’s create the file in the correct directory:

$ mkdir app/serializers
$ touch app/serializers/post_serializer.rb

Then we can write the code for our PostSerializer:

class PostSerializer < ActiveModel::Serializer

  attributes :id, :title, :body, :created_at, :updated_at

end

What the serializers is doing for us here is defining how our JSON will be structured when we call the render method in our PostsController. The top level key will be named after the model (post), and the data attributes we will need inside of it are ID, title, body, and the timestamps.

And…that’s about it. There is more you can do with AMS if you read their documentation, but to get a simple JSON object from your controller, that’s all you absolutely need.

Conclusion

So there you have it. Developing APIs in Rails can be incredibly complex, but these are the basics of what you’ll need to know to turn a boring old Rails app into an API. Whether you want to build and iOS or Android app that pulls data from your Rails server, or just make a set of data more available to other developers, APIs can be incredibly powerful apps. If you want to get really fancy you can even build dual apps that have a Rails API as the back end and a more interactive front end app built in a JavaScript framework like Ember or Angular.

Whatever you’re building an API for, keep in mind that you’re following the same rules as when building any other Rails app: read the documentation, follow the conventions, don’t stress if you break everything. It’s all a part of the process.