Restaurant
Note
This project is archived because I no longer actively use it, and there seems to be no recent activity from other users either. If you are still using it and would like to take over maintenance, please contact me somewhere.
Restaurant serves your data via auto-defined RESTful API on your rails application.
No longer models, controllers, views, routes, and schemas are needed.
Usage
Here is an example that creates a new rails app with Restaurant to provide RESTful API.
$ brew install mongodb
$ mongod --fork
$ rails new example
$ cd example
$ echo 'gem "restaurant"' >> Gemfile
$ bundle install
$ rails g mongoid:config
$ rails c
irb(main):001:0> app.accept = "application/json"
=> "application/json"
irb(main):002:0> app.post "/recipes", recipe: { title: "created" }
=> 201
irb(main):003:0 JSON.parse(app.response.body)
=> {"title"=>"created", "_id"=>"51963fe9f02da4c1f8000001"}
irb(main):004:0> app.get "/recipes/51963fe9f02da4c1f8000001"
=> 200
irb(main):005:0> JSON.parse(app.response.body)
=> {"title"=>"created", "_id"=>"51963fe9f02da4c1f8000001"}
irb(main):006:0> app.put "/recipes/51963fe9f02da4c1f8000001", recipe: { title: "updated" }
=> 204
irb(main):007:0> app.get "/recipes/51963fe9f02da4c1f8000001"
=> 200
irb(main):008:0> JSON.parse(app.response.body)
=> {"title"=>"updated", "_id"=>"51963fe9f02da4c1f8000001"}
irb(main):009:0> app.get "/recipes"
=> 200
irb(main):010:0> JSON.parse(app.response.body)
=> [{"title"=>"updated", "_id"=>"51963fe9f02da4c1f8000001"}]
irb(main):011:0> app.delete "/recipes/51963fe9f02da4c1f8000001"
=> 204
irb(main):012:0> app.get "/recipes"
=> 200
irb(main):013:0> JSON.parse(app.response.body)
=> []
Customize
While Restaurant automagically defines what RESTful API needs, you can do them on your own.
routes
# config/routes.rb
# 1. V1::ResourcesController < ApplicationController are defined if not defined
# 2. The following routes are defined
# GET /v1/:resource -> V1::ReosurcesController#index
# GET /v1/:resource/:id -> V1::ResourcesController#show
# POST /v1/:resource -> V1::ResourcesController#create
# PUT /v1/:resource/:id -> V1::ResourcesController#update
# DELETE /v1/:resource/:id -> V1::ResourcesController#destroy
namespace :v1 do
Restaurant::Router.route(self)
end
# Or customize what you want (e.g. only provides Read API)
# 1. V2::ResourcesController < ApplicationController are defined if not defined
# 2. The following routes are defined
# GET /v2/:resource -> V1::ReosurcesController#index
# GET /v2/:resource/:id -> V1::ResourcesController#show
namespace :v2 do
scope ":resource" do
controller :resources do
get "" => :index
get ":id" => :show
end
end
endcontroller
# Restaurant::Actions provides index, show, create, update, and destroy actions by default.
# Of course you can override them as you like.
module V1
class ResourcesController < ApplicationController
include Restaurant::Actions
respond_to :xml # you can respond to xml requests
def index
respond_with { foo: "bar" }
end
end
endauthentication
Restaurant does not provide any auth layer, but it's easy to add it to your application.
Here is a short example to authenticate users with doorkeeper.
$ echo 'gem "doorkeeper"' >> Gemfile
$ bundle install
$ rails g doorkeeper:install
$ rails g doorkeeper:migration
$ bundle exec rake db:migrate
$ vi app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
doorkeeper_for :all
end
$ rails c
irb(main):001:0> app.accept = "application/json"
=> "application/json"
irb(main):002:0> app.get "/v2/recipes"
=> 401
irb(main):003:0> application = Doorkeeper::Application.create(name: "example", redirect_uri: "http://example.com")
=> #<Doorkeeper::Application ...>
irb(main):004:0> token = application.access_tokens.create
=> #<Doorkeeper::AccessToken ...>
irb(main):005:0> app.get "/v2/recipes", access_token: token.token
=> 200
authorization
Here is an example of a scope-based authorization system.
$ vi app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
doorkeeper_for :all
before_filter :require_authorization
private
def require_authorization
head 403 unless has_authorization?
end
def has_authorization?
doorkeeper_token.scopes.any? do |scope|
if role = Mongoid.default_session["roles"].find(:scope => scope).first
if action_names = role[resources_name]
action_names.include?(action_name)
end
end
end
end
end
$ rails c
irb(main):001:0> app.accept = "application/json"
irb(main):002:0> application = Doorkeeper::Application.create(name: "example", redirect_uri: "http://example.com")
=> #<Doorkeeper::Application ...>
irb(main):003:0> token = application.access_tokens.create(scopes: "admin")
=> #<Doorkeeper::AccessToken ...>
irb(main):004:0> app.get "/v2/recipes", access_token: token.token
=> 403
irb(main):005:0> Mongoid.default_session["roles"].insert(scope: "admin", recipes: ["index", "show"])
=> nil
irb(main):006:0> app.get "/v2/recipes", access_token: token.token
=> 200
irb(main):007:0> app.post "/v2/recipes", access_token: token.token, recipe: { title: "created" }
=> 403