JSON Serializers in a Rails API

amnyrrd

Aaron Minyard

Posted on March 20, 2020

JSON Serializers in a Rails API

This post is meant to serve as an introductory explanation piece on getting started using Rails as an API, and what a serializer is and what they do. If you're scratching your head at Rails as an API, click on and read the tagged link.

Before truly getting started talking about serializers, first let's talk about what JSON actually is. Simply stated, JSON is an abbreviation for JavaScript Object Notation. Taken directly from MDN, "JSON is a syntax for serializing objects, arrays, numbers, strings, booleans, and null. It is based upon JavaScript syntax but is distinct from it: some JavaScript is not JSON." It may be quite obvious after seeing what the abbreviation stands for, but JSON in its original format is just text, written using JavaScript (from here on, 'JS') object notation. In JS, a typical object can look like this:

const me = {
    name: "Aaron Minyard",
    age: 31,
    interests: ["programming", "cycling", "beer"]
}

This same object in true JSON format will look like this:

const me = {
    "name": "Aaron Minyard",
    "age": 31,
    "interests": ["programming", "cycling", "beer"]
}

Obviously, the only difference between the two is that the keys in a JSON object are strings. When using JSON data in standard JS, it is necessary to JSON.parse() your data back into standard JS. The inverse of JSON.parse() is JSON.stringify(). When sending data to whatever server your program is using, JSON.stringify() takes standard JS and "stringifies" it into JSON data.

You may be wondering what serializers are, what they actually accomplish, and why I haven't talked about them yet. Put simply, a serializer is a program that takes a chunk of data and renders said data into data that is easier for computers to read. For our purposes, we will only be talking about JSON.

But first things first. Starting with a new program, we will need to first set up Rails as an API. For our demonstratory application, we will build a (very) rudimentary application that shows beer reviews. If you'd like to code along, first create a new Rails API by typing the following in your terminal:

rails new beer_reviewer --api

From here we will use "rails generate resource" to build out our models, controllers, and migrations. After changing your terminal directory to beer_reviewer, enter each of these three commands into your terminal:

rails g resource beer name brewery style
rails g resource user name age:integer gender location
rails g resource review rating:integer beer:references user:references

In order to run your Rails server (as you will to view what the serializer is doing) you will need to do the following: make sure that you have the gem 'rack-cors' in your gem file, and then bundle install. After you have the gem installed, insert the following code into the config/application.rb file, inside class Application < Rails::Application:

config.middleware.insert_before 0, Rack::Cors do
  allow do
      origins '*'
      resource '*'
  end
end

Now it's time for the more interesting bits: Rails serializers.

From what I understand, Fast JSON is the fastest running serializer and is also quite easy to implement, so for the purposes of this post, we will stick to Fast JSON.

The first step for using Fast JSON is to put the gem 'fast_jsonapi' into your gemfile and then bundle install. Now that we have it installed, we need to generate serializers for each model. Accomplish this by going into your terminal and entering:

rails g serializer Beer
rails g serializer User
rails g serializer Review

After running "rails db:migrate" in your terminal, you will be able to run a rails server like normal, by typing "rails s" into terminal. Predictably, we will also need some seed data so that we can see what the serializer is actually doing. Provided below are 2 instances of each.

Beer.create(name: 'Clouds of Cashmere', brewery: 'Original Pattern', style: 'Hazy IPA')
Beer.create(name: 'Pacifico', brewery: 'Grupo Modelo', style: 'Pilsner')

User.create(name: 'Helen', age: 35, gender: 'female', location: 'San Francisco, CA')
User.create(name: 'Howie', age: 41, gender: 'male', location: 'Oakland, CA')

Review.create(rating: 10, beer_id: 1, user_id: 1)
Review.create(rating: 10, beer_id: 2, user_id: 2)

To see the wizardry provided by serializers, we will need to build out basic controllers as well. For the purpose of this post, all that's needed is an index method in each controller. These will look like this, inserted into each respective controller.

class BeersController < ApplicationController
    def index
        beers = Beer.all
        render json: BeerSerializer.new(beers)
    end
end

class ReviewsController < ApplicationController
    def index
        reviews = Review.all
        render json: ReviewSerializer.new(sightings)
    end
end

class UsersController < ApplicationController
    def index
        users = User.all
        render json: UserSerializer.new(users)
    end
end

Now we need to finish creating our serializers. Each serializer needs to have the attributes we would like to see specified. Say for users we only want to see name and age. Using Fast JSON we would code our serializers like this:

class UserSerializer
  include FastJsonapi::ObjectSerializer
  attributes :name, :age
end

If we then visit localhost:3000/users, we are given this data from the serializer:

{
  "data": [
    {
      "id": "1",
      "type": "user",
      "attributes": {
        "name": "Helen",
        "age": 35
      }
    },
    {
      "id": "2",
      "type": "user",
      "attributes": {
        "name": "Howie",
        "age": 41
      }
    }
  ]
}

If we were to write code to accomplish essentially the same thing without using Fast JSON, we would need to have bulkier methods in our controller, including an initialize method that takes in the data object to be serialized, as well as writing a method that takes in the data object and actually turns it into serialized JSON. While this might not seem terrible for a program like the one I've outlined, the benefits of using a gem that does the work for you are potentially huge. If our program were very large with a bunch of different models, this would save us a lot of time. Rather than writing however many separate methods, all we need to do is specify the attributes we want to see in each serializer and go from there.

Using Rails as an API paired with FastJson can help you write up your program very quickly and efficiently. For more reading on Rails as an API and FastJSon check out the resources below.

Rails API:

  1. How to build a good API using RubyOnRails

  2. Building the Perfect Rails API Only App

FastJSON/Serialization:

  1. JSON Serialization in Rails

  2. Fast JSON API serialization with Ruby on Rails

  3. The FastJSON API on GitHub

💖 💪 🙅 🚩
amnyrrd
Aaron Minyard

Posted on March 20, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

JSON Serializers in a Rails API
beginners JSON Serializers in a Rails API

March 20, 2020