Module: Sinatra::RestAPI

Defined in:
lib/sinatra/restapi.rb

Overview

## RestAPI [module] A plugin for providing rest API to models. Great for Backbone.js.

To use this, simply ‘register` it to your Sinatra Application. You can then use `rest_create` and `rest_resource` to create your routes.

require 'sinatra/restapi'

class App < Sinatra::Base
  register Sinatra::RestAPI
end

### RestAPI example Here’s a simple example of how to use Backbone models with RestAPI. Also see the [example application] included in the gem.

[ex]: github.com/rstacruz/sinatra-backbone/tree/master/examples/restapi

#### Model setup Let’s say you have a ‘Book` model in your application. Let’s use [Sequel] for this example, but feel free to use any other ORM that is ActiveModel-compatible.

You will need to define ‘to_hash` in your model.

db = Sequel.connect(...)

db.create_table :books do
  primary_key :id
  String :title
  String :author
end

class Book < Sequel::Model
  # ...
  def to_hash
    { :title => title, :author => author, :id => id }
  end
end

[sq]: sequel.rubyforge.org

#### Sinatra To provide some routes for Backbone models, use ‘rest_resource` and `rest_create`:

require 'sinatra/restapi'

class App < Sinatra::Base
  register Sinatra::RestAPI

  rest_create '/book' do
    Book.new
  end

  rest_resource '/book/:id' do |id|
    Book.find(:id => id)
  end
end

#### JavaScript In your JavaScript files, let’s make a corresponding model.

Book = Backbone.Model.extend({
  urlRoot: '/book'
});

Now you may create a new book through your JavaScript:

book = new Book;
book.set({ title: "Darkly Dreaming Dexter", author: "Jeff Lindsay" });
book.save();

// In Ruby, equivalent to:
// book = Book.new
// book.title  = "Darkly Dreaming Dexter"
// book.author = "Jeff Lindsay"
// book.save

Or you may retrieve new items. Note that in this example, since we defined ‘urlRoot()` but not `url()`, the model URL with default to `/[urlRoot]/`.

book = new Book({ id: 1 });
book.fetch();

// In Ruby, equivalent to:
// Book.find(:id => 1)

Deletes will work just like how you would expect it:

book.destroy();

Defined Under Namespace

Modules: Helpers

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.registered(app) ⇒ Object



96
97
98
# File 'lib/sinatra/restapi.rb', line 96

def self.registered(app)
  app.helpers Helpers
end

Instance Method Details

#rest_create(path, options = {}, &blk) ⇒ Object

### rest_create(path, &block) [method] Creates a create route on the given ‘path`.

This creates a ‘POST` route in /documents that accepts JSON data. This route will return the created object as JSON.

When getting a request, it does the following:

* A new object is created by *yielding* the block you give. (Let's
  call it `object`.)

* For each of the attributes, it uses the `attrib_name=` method in
  your record. For instance, for an attrib like `title`, it wil lbe
  calling `object.title = "hello"`.

* if `object.valid?` returns false, it returns an error 400.

* `object.save` will then be called.

* `object`'s contents will then be returned to the client as JSON.

See the example.

class App < Sinatra::Base
  rest_create "/documents" do
    Document.new
  end
end


129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/sinatra/restapi.rb', line 129

def rest_create(path, options={}, &blk)
  # Create
  post path do
    @object = yield
    rest_params.each { |k, v| @object.send :"#{k}=", v }

    return 400, @object.errors.to_json  unless @object.valid?

    @object.save
    rest_respond @object.to_hash
  end
end

#rest_delete(path, options = {}, &blk) ⇒ Object

### rest_delete(path, &block) [method] This is the same as ‘rest_resource`, but only handles DELETE (edit) requests. This uses `Model#destroy` on your model.



212
213
214
215
216
217
218
# File 'lib/sinatra/restapi.rb', line 212

def rest_delete(path, options={}, &blk)
  delete path do |*args|
    @object = yield(*args) or pass
    @object.destroy
    rest_respond :result => :success
  end
end

#rest_edit(path, options = {}, &blk) ⇒ Object

### rest_edit(path, &block) [method] This is the same as ‘rest_resource`, but only handles PUT/POST (edit) requests.



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/sinatra/restapi.rb', line 192

def rest_edit(path, options={}, &blk)
  callback = Proc.new { |*args|
    @object = yield(*args) or pass
    rest_params.each { |k, v| @object.send :"#{k}=", v  unless k == 'id' }

    return 400, @object.errors.to_json  unless @object.valid?

    @object.save
    rest_respond @object
  }

  # Make it work with `Backbone.emulateHTTP` on.
  put  path, &callback
  post path, &callback
end

#rest_get(path, options = {}, &blk) ⇒ Object

### rest_get(path, &block) [method] This is the same as ‘rest_resource`, but only handles GET requests.



181
182
183
184
185
186
# File 'lib/sinatra/restapi.rb', line 181

def rest_get(path, options={}, &blk)
  get path do |*args|
    @object = yield(*args) or pass
    rest_respond @object
  end
end

#rest_resource(path, options = {}, &blk) ⇒ Object

### rest_resource(path, &block) [method] Creates a get, edit and delete route on the given ‘path`.

The block given will be yielded to do a record lookup. If the block returns ‘nil`, RestAPI will return a 404.

In the example, it creates routes for ‘/document/:id` to accept HTTP GET (for object retrieval), PUT (for editing), and DELETE (for destroying).

Your model needs to implement the following methods:

* `save` (called on edit)
* `destroy` (called on delete)
* `<attrib_name_here>=` (called for each of the attributes on edit)

If you only want to create routes for only one or two of the actions, you may individually use:

* `rest_get`
* `rest_edit`
* `rest_delete`

All the methods above take the same arguments as ‘rest_resource`.

class App < Sinatra::Base
  rest_resource "/document/:id" do |id|
    Document.find(:id => id)
  end
end


172
173
174
175
176
# File 'lib/sinatra/restapi.rb', line 172

def rest_resource(path, options={}, &blk)
  rest_get    path, options, &blk
  rest_edit   path, options, &blk
  rest_delete path, options, &blk
end