Register Now

Ruby on Rails Developer Series: Spinning Up a JSON API in Minutes

Development

Reading Time: 4 minutes

Welcome to the first of four Ruby on Rails Developer Series. In this series, the goal is to outline how to strengthen your API with Postgres, how to dockerize your project and add security layers to mitigate attacks to your application. In this article, we’ll cycle through building a quick API-only application uses the JSON API from Active Model Serializer. Then construct a basic CRUD Controller API example on retrieving the User information. While the process is outlined and best practices are used. The goal of the series is to make you feel confident as an engineer in building a structured project with Ruby on Rails.

Let’s Begin

Let’s start off by using the --api command in the console to provision an api only preset.

rails new rails-json-api-test --api

This will generate the following:

app/controllers

app/assets

app/helpers

app/models

config

Objective CRUD

Our goal is to use the ActiveModel::Serializer – JSON API – which is included by default in your Gemfile when you create an application using the --api directive. We will then work toward spinning up a basic CRUD endpoint for a user.

Below is the endpoint we plan to implement and http methods we plan to send to the API.

Path: /api/v1/users

GET
POST
PUT
DELETE

Next, we need to generate the basic User Model that we want to create using the rails generate command for Models:

First, we need to set up our database. In this example, we will be using PG (Postgres) and will set up the minimum requirement to allow us to proceed to build our API and come back to this in the next article.

gem pg

Then we need to set up our database.yml file

default: &default
  adapter: postgresql
  host: localhost
  port: 5432
  encoding: utf8
  pool: 5
  database: rails-json-api
  username: development
  password: development

development: &default
  adapter: postgresql
  host: localhost
  port: 5432
  encoding: utf8
  pool: 5
  database: rails-json-api-dev
  username: development
  password: development

Then we’re ready to create the database and build our table.

rake db:create

rails g model User first_name:string last_name:string email:string

That should generate something like this:

  invoke  active_record
  create    db/migrate/20190521020122_create_users.rb
  create    app/models/user.rb
  invoke    test_unit
  create      test/models/user_test.rb
  create      test/fixtures/users.yml

Now let’s work on the serializer side of things of how the API will respond to the request.

We will want to uncheck this in the gemfile:

gem 'active_model_serializers', '~> 0.10.0'

When we make the controller we will need the namespaces to be setup:

For the namespace to change fromApi::V1::UsersController to API::V1:UsersController we need to modify the inflection file which was generated in config/initializers/inflections.rb. We will then need to uncomment and add this to the file:

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.acronym 'API'
end

Lock down your routes to ONLY ALLOW these method requests.

    Rails.application.routes.draw do
  namespace :api, path: '' do
    namespace :v1 do
      resources :users, only: [:index, :show, :create, :update, :destroy]
    end
  end
end

This is what our controller looks like to be able to support our methods:

class API::V1::UsersController < ApplicationController
  rescue_from ActiveRecord::RecordNotFound, with: :record_not_found

  def index
    users = User.all
    render json: users, each_serializer: UserSerializer, adapter: :json_api, status: 200
  end

  def show
    user = User.find(params[:id])
    render json: user, serializer: UserSerializer, adapter: :json_api, status: 200
  end

  def create
    user = User.new(user_params)
    render json: user, serializer: UserSerializer, adapter: :json_api, status: 200 if user.save!
  end

  def update
    user = User.find(params[:id])
    render json: user, serializer: UserSerializer, adapter: :json_api, status: 200 if user.update(user_params)
  end

  def destroy
    user = User.find(params[:id])
    render json: user, serializer: UserSerializer, adapter: :json_api, status: 200 if user.destroy!
  end

  private

  def record_not_found
    render json: { message: 'Record Not Found!'}, adapter: :json_api, status: 404
  end

end

Responding with JSON

JSON API is a format that works to optimize http(s) requests mainly to promote more productivity and efficiency. JSON API comes with strong caching functionality as data changes affect fewer resources.

You can simply add this to the Serializer to implement basic key-based cache expiration:

  cache key: 'user', expires_in: 3.hours

Conclusion

https://media.giphy.com/media/l4FBdfoF9kNr1yw2A/giphy.gif

We have just spun up a JSON API in a few minutes for our User Table. We have left some items for the next part of the series to strengthen our API-based application. In the next article, we will further work on building a strong JSON API and using Postgres to your advantage.

This project is available on my repo here

Additional resources

  1. Learn how to tame the Jenkins JSON API with Depth and “Tree.”
  2. How do JSON and XML compare? Find out here.
  3. Discover what JSON Schema is and what role it plays.

Subscribe via Email

Over 60,000 people from companies like Netflix, Apple, Spotify and O'Reilly are reading our articles.
Subscribe to receive a weekly newsletter with articles around Continuous Integration, Docker, and software development best practices.



We promise that we won't spam you. You can unsubscribe any time.

Join the Discussion

Leave us some comments on what you think about this topic or if you like to add something.