Decoupling GUI from API in Ruby on Rails 3
Having built web applications with Rails 3 and Sencha ExtJS for the past year or so, I developed a simple way to decouple GUI concerns from APIs:
If a format is specified in the requested URI, then serve the API. Otherwise, serve the GUI while indicating that the response is non-authoritative, using HTTP status code 203.
The implementation, from routes to controllers, is demonstrated below.
For example, when GET /users
is requested, the GUI is served; but when
GET /users.json
is requested, the API is served. Similarly, when POST
/users
is requested, the GUI is served; but when POST /users.json
is
requested, the API is served and it responds with the newly created user.
config/routes.rb
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
root :to => 'application#index'
# pass unknown URLs to GUI (HTML5 history.pushState)
# http://railscasts.com/episodes/46-catch-all-route
match '*path' => 'application#index'
app/controllers/application_controller.rb
# serve GUI when no format is specified
before_filter do
unless params[:format]
render nothing: true, layout: true, status: :non_authoritative_information
end
end
# serve API when a format is specified
def index
respond_with nil, location: nil, status: :not_implemented
end
alias new index
alias create index
alias show index
alias edit index
alias update index
alias destroy index
# serve these formats in respond_with()
respond_to :json
app/controllers/users_controller.rb
class UsersController < ApplicationController
def create
user = User.new(params[:user])
respond_with(
{
success: !!user.save,
errors: user.errors,
user: user,
},
location: url_for(user)
)
end
end