Thursday, 15 January 2015

API Development Restfull vs Facebook style


In the last months I developed mainly API's using grape gem and their related gems.

In this blog post I will express my opinion how to organise the API which manages the entities.

Generally speaking I like the REST concept and I organize my API to conform that way. For cases when there are no association among the entities this philosophy is good enough and clear.

However I like the API to reflect the associations when we are dealing with has_many or has_and_belongs_to_many associations. Just like in case of  Facebook Graph API. In these cases I find that style more intuitive and I am following that style whenever I deal with associations.

Examples:

Lets suppose that cars and manufacturers can be reviewed.

class Car < ActiveRecord::Base
  has_many :reviews, as: :reviewable

class Manufacturer < ActiveRecord::Base
  has_many :reviews, as: :reviewable

class Review < ActiveRecord::Base
  belongs_to :user
  belongs_to :reviewable, polymorphic: true

In this case the review API would be:
  • creation of reviews:
    POST /api/cars/{id}/reviews
    POST /api/manufacturers/{id}/reviews
  • retrieval of reviews:
    GET /api/cars/{id}/reviews
    GET /api/manufacturers/{id}/reviews
  • deletion of reviews:
    DELETE /api/reviews/{id}


In the classic restful style the review creation would be:

    params do
      requires :comment, type: String, desc: "The comment"
      requires :reviewable_id, type: Integer, desc: "The id of a reviewable entity"
      requires :reviewable_type, type: String, desc: "The type of a reviewable entity"
    end
    POST /api/reviews

Both solutions have pros and cons. The restful style is more DRY. The Facebook Graph Api style relieves more information about the associations ergo it is more intuitive and easier to use.

Happy coding :)



Friday, 2 January 2015

Specing the API


When you cover your API with specs the first rule is to cover everything. 
Since the API can be called by third parties you need to be sure what is happening in every case. You must be able to reproduce every scenario any time and you must have the same results. :) Does it seems scientific? Well... Indeed it is.

Let me show you some examples:
-You might need to check that only the calls with developer key can access the API. In the opposite case the response is 401, it is still a JSON and maybe an audit log is created.
-You might need to check that the user is authenticated. If not then the response is 401, it is still a JSON and again an audit log is created.
-If some of the parameters are missing or wrong then the response is 400, it is still a JSON and an audit log is created by logging all the incoming parameters.
-If everything is alright then the response is 200/201, the response is a JSON and the entities are massaged as needed by that specific case.

You also need to keep your specs DRY
This will reduce maintenance effort of the test code and it will keep your specs more readable and you will have easy time to add new features and you will feel more happy and in control.

As you can see the above steps like checking the response code, checking if the response format is JSON, checking that the audit log is created are repetitive tasks and can be DRY-ed with rspecs shared examples. The only specific thing which changes from one api endpoint to another is "the entities are massaged as needed by that specific case".

RSpec.shared_examples "returning 401" do
  specify "returns 401" do
    api_call params, developer_header
    expect(response.status).to eq(401)
  end
end
RSpec.shared_examples "being JSON" do
  specify 'returns JSON' do
    api_call params, developer_header
    expect { JSON.parse(response.body) }.not_to raise_error
  end
end
...

Then in your specs you can use these shared examples in particular cases:

context '/API/learn_by_playing/' do
  def api_call *params
    get "/api/learn_by_playing", *params
  end
  let(:api_key) { create :apikey }
  let(:developer_header) { {'Authorization' => api_key.token} }
  context 'GET' do
    let(:required_params) do
      {
        :first_name => 'Botond',
        :last_name => "Orban"
      }
    end
    let(:params) { required_params }

    it_behaves_like 'restricted for developers'

    context 'wrong parameters' do
      required_params.keys.each do |s|
        context 'when the #{s} parameter is blank' do
          let(:params) { required_params.merge({s => ''}) }
          it_behaves_like 'returning 400'
          it_behaves_like 'being JSON'
          it_behaves_like 'creating an audit log'
        end
        context 'when the #{s} parameter is missing' do
          let(:params) { required_params.except(s) }
          it_behaves_like 'returning 400'
          it_behaves_like 'being JSON'
          it_behaves_like 'creating an audit log'
        end
      end
    end
    context 'valid params' do
      specify '...whatever you need to really assert for in this particular case...' do
        api_call params, developer_header
        expect ...
      end
    end
  end
end

As you can see from the above example using Rspec.shared examples a lot of repetitive lines from your Rspec can be thrown out.

On one of my projects I managed to reduce the specs size by 20% and raise the visibility a lot :) I can't measure and therefore I can't express in numbers what "a lot" means but everybody was satisfied  and pleased with the result.

Professional DRY hacking ;)

Monday, 29 December 2014

Use logger.debug rather than puts!

It is often tempting to use puts in the ruby code to debug the informations.

I like logging instead because:
-allows the filtering capability
-allows formatting abilities
-with a little tweak it takes the same amount of effort than puts
-it is an already invented and well tested system

It is much better in short. So whenever is a logger system available I use that.

logger.debug 'doing this and that'

It seem to me too much to type at first, therefore I created a sublime logger snippet which accelerated typing. I created another one for those cases where I need to implicitly reference the Rails.logger.

;)

Sunday, 28 December 2014

API Development in Ruby On Rails, Nested Entities

There are times when there is one-to-many association amongst the entities. And the mobile developer needs to show all of them in one screen. In these cases it is very easy to fell into the bad habit to execute n+1 queries from mobile side toward the server or from the server to the sql-server.

Here are the entities:

class DetailedGameEntity < Grape::Entity
  ...
  expose :reviews, using: ReviewEntity do |game, options|
    game.reviews
  end
end

class ReviewPresenter < Grape::Entity
  expose :user_id, as: :owner_id
  expose :comment
  expose :rating

  expose :image_urls do |review, options|
    review.images.map{|image| image.image}
  end
end

They are designed to return everything the mobile screen needs. The games contains their reviews. And the reviews contain their images. So in one query the whole mobile screen can be populated.

Let's see how a programmer in a hurry develops all this API:

games = Game.actual.limit(500)
present games, with: DetailedGameEntity

By developing the API this way the call will result in these queries:
...
  Review Load (0.5ms)  SELECT "reviews".* FROM "reviews"  WHERE "reviews"."reviewable_id" = $1 AND "reviews"."reviewable_type" = $2  [["reviewable_id", 2359], ["reviewable_type", "Game"]]
  Review Load (0.4ms)  SELECT "reviews".* FROM "reviews"  WHERE "reviews"."reviewable_id" = $1 AND "reviews"."reviewable_type" = $2  [["reviewable_id", 2358], ["reviewable_type", "Game"]]
...

As you can see for each returned game game another select is executed to fetch the belonging reviews. The same is done to fetch the belonging user and to fetch the images belonging to the review. This is a very ineffective way because as the review count grows more and more queries need to be executed. This problem is called n+1 query problem.

I do this in my code in these cases:

games = Game.actual.limit(500)
games = games.includes(reviews: [:images, :user] )
present games, with: DetailedGameEntity

The above code will do this sql query:

 Review Load (1.0ms)  SELECT "reviews".* FROM "reviews"  WHERE "reviews"."reviewable_type" = 'Schedule' AND "reviews"."reviewable_id" IN (2195, 2198, 2197, 9567, 9572, 9573, 9574, 9575, 9576, 9571, 9570, 9569, 9568, 2196, 2204, 2210, 2211, ...

So, the underlying Rails code will execute only one query per entity.

It is nice, isn't it?

Please use it ;)