I need a suggestion on how to implement "client-server" web apps in ruby. Any guides and best practices are highly appreciated. I'm interested both in Ruby ways and gems required as it is a desired platform, and in general ways and logic to implement such things.
I'm not an excellent ruby programmer or a skilled system designer with years of expirience sadly so I really need your help as I still hope this thing would shine in the end.
The current look of the application should be like this:
DB + Auth DB <-> API App <-> Other Apps:
API App: looks like the best tool to make it is Sinatra. The questions are:
Other Apps: mainly web-based UIs. The logical selection for this part is Rails. The main question is how to implement client-side auth check. Devise is cool, but is it possible to make it work with token, or is it more suitable tool?
Okay, this is going to be a bit longer:
If you are already familiar with Rails, you can have a look at the Rails API gem. The project strives to remove additional cruft from Rails which is not needed for a JSON-based RESTful API.
This may sound smooth, but it has it's downsides. First and foremost, you have the readd everything that is needed for basic rails functionality, that you may be accustomed to, e.g. respond_to
. This can be a bit tricky, but is pretty straightforward when you find out which rails module originally provided the functionality usually bundled in Rails within the ActionController::Base
.
That being said, let me give you an example of what i did for a small API project I did last week out of curiosity:
We have a mainly finished Rails App. It all works fine, but it is basically monolithic. Everything is served by the Rails Framework. Luckily for us, all the model logic is bundled into a gem called core
. the application essentially lets logged in customers create products which are than searchable through an end user view.
The goal was to provide a RESTful API for this, which can handle concurrency and larger data files (i.e. CSV, XLS) a little bit more efficiently.
The design goal let me to the Rails API gem. The basic installation works like in Rails, except the script is called rails-api
, i.e.:
rails-api new jsonapi
The advantage for me here was that I could use the core
from the other application, but nothing would stop me from just introducing my own models to the jsonapi
application.
That being said, you can do all the standard Rails goodies, like routing, etc. It follows the same convention. then again, standard routes initially react to JSON only, which can be a bit confusing at times.
Let me give you an example of the API Controller that handles products:
class ProductsController < ApplicationController
include ActionController::HttpAuthentication::Token
before_filter :find_product, :except => [:create, :index]
def index
render :json => @products
end
def create
@product = product.new params[:product]
if @product.save
render :json => @product, :status => :created
else
render :json => @product.errors, :status => :unprocessable_entity
end
end
def show
render :json => @product
end
def update
if @product.update_attributes params[:product]
render :json => @product, :status => :ok
else
render :json => @product.errors
end
end
def destroy
if @product.destroy
render :json => @product, :status => :ok
else
render :json => {:note => I18n.t("messages.deletion_impossible")}, :status => :unprocessable_entity
end
end
protected
def find_product
@product = Product.find params[:id]
end
end
It is nothing special. The only thing to note is the second line where ActionController::HttpAuthentication::Token
is included explicitly. This is so that your aPI may be secured by HTTP Token. If you want to know more about securing an API, I suggest Ryan Bates' Guide on Railscasts.
In essential, you provide a before filter in the ApplicationController
like this:
class ApplicationController < ActionController::API
include ActionController::HttpAuthentication::Token::ControllerMethods
[...]
before_filter :restrict_access
[...]
def restrict_access
authenticate_or_request_with_http_token do |token, options|
# see if key is valid.
end
end
end
Again, note the second line, you have to include the ControllerMethods
manually, otherwise no controller will know about authenticate_or_request_with_http_token
.
You may know extend the API based on the Rails conventions. It works exactly the same way, with the exception that some stuff is intentionally missing by default. I suggest adding JBuilder (Railscast), if you need more flexibility in your JSON Templates.
Personally, there is a lot of choice when it comes to clients. Ultimately I find that it comes down to what you like most. I can personally recommend a small node.js layer on top of the Rails API which then gets a single page application based on backbone.js in front of it. You can also try AngularJS if you like. You can also build another Rails App around it and call the API from within your controller actions.
It also depends on what platform you want to target - a native application for iOS/Android comes to mind.
The choice I made was node.js + backbone. It currently makes the most sense for me at the time and for the project. The node layer essentially holds the Token necessary to communicate with the API and the backbone application has a small library to talk with the node layer. It can however be a double edged sword, depending on how complex your API will be. For a small example this seems to be fine, but there can be a lot of code duplication just to put the calls from the backbone application through to the Rails API.
For authentication you can make customer based API-Keys (Tokens) and then limit the controller logic to only accept data operations which are allowed with that key. You could than manage the session via the node layer. Edit: This is authorization, not authentication. Nothing actually stops you from using Authlogic with Rails API - i have not tested it, but it should work.
I confess that i have not finished this part yet - I hope others can answer this architectural question :-)
I hope I could provide some insights.
P.S.: If you want to test your API i highly recommend httpie (It's awesome!)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With