Developing an RDBMS backed API Resource in Rails

Building an API backed up by some Data has become kind of compulsory nowadays. Most application require to expose their data and services to other applications/clients via an API. I was recently working on such a project where I have to build an API backend for an application, backed up by RDBMS (Postgresql in my case).
I’ve used the latest Rails framework along with Postgresql as my default database at the back end.

Let’s walk you through the fairly simple and concise steps to build an API backed by an RDBMS in no time.

First of all , create a directory and name it anything appropriate. I’m gonna name mine ‘demoApp’.

Then cd into this directory and create a Rails API project. Since it’s not a fully blown Rails application and just an API, we will make use of ‘rails-api’ gem to generate this project.

So we type into the terminal:

rails-api new . -T -d postgresql

So this will generate us a project without the artifacts of a Rails app, and just the necessary stuff for an API.
‘-T’ here indicates that I don’t intend to use the default testing framework provided by Rails, which is minitest, since I plan to use RSpec. And by RSpec you might have guessed I’m gonna build this project in a TDD(Test Driven Development) fashion.

‘-d’ however indicates that I intend to use Postgresql as my test and Development database. The reason I did this so is because I want to keep all the dependencies of my project as close as possible to that of the production environment.This will save me from hassle of transitioning my app from Development level dependencies to production level dependencies when I deeply my app to production. (E.g heroku doesn’t support sqlite and require you to stick with Postgresql)

So I’ll head over to my Gemfile in the project and add gem ‘rspec’ and then bundle install.

Once the gem is installed I can go ahead and invoke RSpec in my application. I’ll put in the terminal

rails g rspec:install

This is gonna generate a ‘spec’ folder in our project root directory which contain all the tests for our application.

So next we will generate an RSpec test for our RDBMS backed API. Our API is fairly simple and currently I’d like my API to fulfill following requirements:

  • It should be able to create an RDBMS backed model
  • It should expose and RDBMS-backed API resource accessible via HTTP, and return us a result in form of JSON

That’s fairly simple at this stage. So let’s go ahead in the terminal and generate our test:

    rails g rspec:request APIDevelopment

This instantiate our ‘api_devemopment.rb’ test in a ‘request’ folder under spec directory. It would generate some boilerplate code for us, but we’ll stick to our requirements.

So implementation of our first requirement looks like this:

it 'expose RDBMS-backed API resource' do
      object = Foo.create(name: 'test')
      expect(foos_path).to eq('/api/foos')
      get foo_path(object.id)
      expect(response).to have_http_status(:ok)
    end

Basically what this test does is just create an instance from a ‘Foo’ model and then try to retrieve it via an ‘id’ and ‘name’ in order to make sure our model is right in place.

Next we make sure that we need to expose this RDBMS resource ‘Foo’ via an API and render it through a JSON upon an HTTP request to ‘/api/foos’ URI.
So we put that test in place in our ‘api_development.rb’ file.

it 'expose RDBMS-backed API resource' do      
  object = Foo.create(name: 'test')      
  expect(foos_path).to eq('/api/foos')      
  get foo_path(object.id)      
  expect(response).to have_http_status(:ok)   
end

This test again begins with instantiating a model ‘Foo’ and then retrieves its path via ‘foo_path’ and verifies either it’s accessible using the URI ‘/api/foos’ or not.
It further verifies that the resource is accessible via an HTTP request and returns an HTTP status of ‘ok’ i.e. request was successful(success code: 200).

If we run our tests right now, of course it’s gonna fail since we haven’t implemented the functionality yet. So, at this point in time we’re ready to code against our requirements and verify using these test until we get success.

So now, we’ll go ahead and generate our model and all the artifacts along with it using a scaffold. However we’ll skip some of the artifacts generated by rails scaffold command by default. We will skip artifacts related to controller specs, requests specs and routing specs, since it’s just an API project and not a fully blown rails app.

I can accomplish that via following command :

rails g scaffold Foo name --no-request-specs --no-routing-specs --no-controller-specs

As soon as you enter this command you can visualize artifacts it creates in the project in the terminal. This scaffold is also going to generate a model spec named ‘foo_spec’ in our ‘spec’ folder. I’m gonna delete that model file since we don’t need it. We’d also delete the views (if generated) in the spec directory since we got nothing to do with them.
Now before we run out migration we’ll take a look at our ‘database.yml’ file and add configurations for our database, since we are using Postgresql. Make sure you have the following configurations in place:

default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV['POSTGRES_USER']%>
  password: <%= ENV['POSTGRES_PASSWORD']%>
  host: <%= ENV['POSTGRES_HOST']%>
development:
  <

Next I run

rails db:create 
rails db:migrate

to create my test and development environment database and apply migrations generated by scaffolding.

Now, our database is in place, our migrations are applied, it’s time to test our code. To test simple type:

 rspec

in the terminal.
We will have one passing and one failing test at this point. One that fails specifies that it expected ‘/api/foos’ as a path to ‘Foo’ resource but actually got ‘foos’, since this is how rails generate the default URIs for us.

We can fix that by simply adding a scope to our route to have that request delegated to our resource via ‘/api/foos’ instead of ‘foos’. So I’m gonna head to my ‘routes.rb’ file and add a scope for ‘/api/foos’. It looked like as follows :

 
Rails.application.routes.draw do
  scope :api, defaults: {format: :json} do
    resources :foos, except: [:new, :edit]
  end
end

This also indicates that the request to this URI expects a JSON response.

Now we’ll head to our ‘foos_controller’ and configure out actions according to the expected response by our api URIs.
So our controller looks like this :

class FoosController < ApplicationController
  before_action :set_foo, only: [:show, :edit, :update, :destroy]
  def index
    @foos = Foo.all
    render json: @foos
  end
  def show
    render json: @foos
  end
  def new
    @foo = Foo.new
  end
  def edit
  end
  def create
    @foo = Foo.new(foo_params)
    respond_to do |format|
      if @foo.save
        format.json { render :show, status: :created, location: @foo }
      else
        format.json { render json: @foo.errors, status: :unprocessable_entity }
      end
    end
  end
  def update
    respond_to do |format|
      if @foo.update(foo_params)
        format.json { render :show, status: :ok, location: @foo }
      else
       format.json { render json: @foo.errors, status: :unprocessable_entity }
      end
    end
  end
  def destroy
    @foo.destroy
    respond_to do |format|
      format.json { head :no_content }
    end
  end
  private
  def set_foo
    @foo = Foo.find(params[:id])
  end

  def foo_params
    params.require(:foo).permit(:name)
  end
end

This may look intimidating but we’re simply delegating our controller actions to render json views and remove any artifacts related to rendering html, since they are not applicable here.

For the test example we’ll head to our application console and create a sample instance in our database, so that we can visualize it when running our app locally for test purposes.

 Foo.create(:name=>"test")

Now we’ll run our test finally , and hopefully the tests shall pass and we’ll run our app locally. In the terminal invoke :

rails s

We can invoke out api locally in a browser via “http://localhost:3000/api/foos”.We’ll get the response in your browser as follows.

// 20170817235053
// http://localhost:3000/api/foos
[
  {
    "id": 1,
    "name": "test",
    "created_at": "2017-08-17T17:57:15.187Z",
    "updated_at": "2017-08-17T17:57:15.187Z"
  }
]

Moreover while your server is still running , get to rails console and invoke your api via issuing a get request from Ruby script.

response = HTTParty.get('http://localhost:3000/api/foos')

You should get a response like that in form of a json object :

{"id"=>1, "name"=>"test", "created_at"=>"2017-08-17T17:57:15.187Z", "updated_at"=>"2017-08-17T17:57:15.187Z"}

So our API is final and ready. We successfully built it in a TDD fashion. It’s a fairly simple API, but the main purpose was to demonstrate the streamline Test Driven Development Practice to build APPS and APIs. You can safely deploy this app seamlessly in one single step since all the dependencies we use for this API were that of the production and there will be no extra dependency management to be taken care of.

I hope you like this post about building RDBMS backed APIs. Next we will cover MongoDB-backed API development using Rails, or a non-sql backed approach of developing RESTful APIs using Rails. Stay tuned and let me know about your thoughts and suggestions in comments. Happy coding

 

Shabbir

I'm student of computer Sciences and Self Taught Developer, dedicated to Self Education via MOOCs :)

 

Leave a Reply

Your email address will not be published. Required fields are marked *