Building a JSON REST API with Rails 5

A guide on how to create a proper JSON REST API using Rails 5.

Ruby on Rails is well established as a great framework for quick and enjoyable web application development, but most developers tend to ignore it when it comes to creating an API. For me, it makes total sense to 1) Write my APIs in the language i am most practiced in 2) Keep a consistent style across the backend of all of my projects and 3) Make use of all of the helpful generators and comforts I have at my disposal when I develop with Rails, which is why I prefer to make any REST API inside of Rails if that's reasonable for the project.

When I was researching this guide to try to honestly gauge whether or not people could use it, I found many comments from developers on Reddit and Stack Overflow that didn't even know the --api flag existed. Well, it does - and here's how to use it.

Step one - Generate a new rails app with the --api flag, and as usual i'm also going to be using PostgresQL for my database.

rails new apidemo --api -d postgresql

The --api flag in our new app generator tells Rails a few things about our project. Firstly, that we don't need to create views, helpers or assets when we generate a new resource, and also that we don't need to bother with sessions or any cookies for that matter.

The API we create here will interact with an object we'll call Widgets in our database, so let's cd into our app, create our database and scaffold out our widgets with just a title for now.

cd apidemo
rails db:create
rails g scaffold widget title
rails db:migrate

Because we're in API mode, our scaffolder will only generate a migration to add a Widget table into our database with the title column (and as always it'll also have an id, created_at, and updated_at column), it will generate our Widget model and test model, it'll add resource routes for widgets (we'll namespace these in a moment) and the most important part - it will generate a widgets controller which is already set up to respond to incoming requests for all CRUD functionality with JSON.

If you jump into your widgets controller, you'll see it's nicely commented with with all of the available actions - for example, if you send a GET request to /widgets.json, it'll render out all of our widgets in JSON format, but you're probably thinking that doesn't look like a finished url, and you're right. When dealing with any normal REST API, the urls you're calling usually point to the api and a version, so we're going to namespace our resource routes to help us later when we decide to add more features or functionality. First things first, we need to create our api directory inside our controllers directory, and then a v1 directory inside of that, so in your terminal run mkdir app/controllers/api; mkdir app/controllers/api/v1. Now we just move our widgets controller into the new v1 directory and wrap it in our namespace module, it should look like this:

# inside app/controllers/api/v1/widgets_controller.rb

module Api::V1
  class WidgetsController < ApplicationController

Now jump into your config/routes.rb file and if should look like this:

Rails.application.routes.draw do
  resources :widgets
  # For details on the DSL available within this file, see

All you need to do is namespace that resource route like so:

Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      resources :widgets
  # For details on the DSL available within this file, see

Now let's seed in a test widget, in your terminal run rails c then Widget.create(title: "Test widget") then quit the console and boot up your rails server with rails s.

Now just open up a browser and navigate to yourapp/api/v1/widgets and you'll see the widget you just created returned to you in JSON format.

    "id": 1,
    "title": "Test widget",
    "created_at": "2019-12-15T17:51:40.645Z",
    "updated_at": "2019-12-15T17:51:40.645Z"

Now you have a basic working JSON REST API running entirely in Rails. You can later expand upon this by adding users with authenticated credentials or more complex features like limited or queried results.