Restful Query
What
Restful Query is a module that when included in ActiveRecord or Sequel (as of 0.3.0) supplies an easy and safe way to query a database through a RESTful resource.
Why
The general RESTful resource generated by Rails and widely used across the community supplies only basic CRUD (Create Read Update Delete) functionality. The index action usually provides a list (probably paginated) of all the records for a given resource or within a given scope. Restful Query provides an easy way to create a RESTful API for querying records for a given resource.
For example, given a resource of Book, say you want to get a list of all Books whose created or added to the system in the last two weeks. The common solution would be to create another action on the resource for querying the books by date. With Restful Query its as easy as:
/books?query[created_at][gt]=2 weeks ago
Restful Query allows you to query the books by any and as many parameters you want and want to allow.
Usage
RestfulQuery provides extensions for both ActiveRecord and Sequel. The only difference is how to enable the extension.
With ActiveRecord/Rails
Including Restful Query in your Rails project is easy. Install it as a plugin or a gem in your app.
In the ActiveRecord model you want to query, invoke the can_query macro:
class Book < ActiveRecord::Base
can_query
end
This will add a few methods to your model, notably the named_scope restful_query
With Sequel
RestfulQuery includes an extension for Sequel. Once the gem is installed:
require 'sequel/extensions/restful_query'
This extends the Sequel::Dataset class, allowing you to filter/order a dataset using the restful_query
method.
General Usage
restful_query
takes a hash with a special format and converts it into a conditions array. The format is intended to be easy to interpret and read within the URL as well as be easy to pass as Rails-like form params.
The ruby hash should look something like:
params[:query] = {'column' => {'operator' => 'value', ...}, ...}
Which looks like this before being coverted by ActionController’s params parser:
?query[column][operator]=value&...
A query can be made up of as many operators
on as many columns
as you like.
A column
is a literal column in the database. You can query across tables by passing the :include
option to the can_query
macro. You can also exclude columns you dont want queried (password, private info) by passing :exclude_columns
to can_query
with an array of column names.
An operator
is one of the following:
Restful Query | SQL | English |
---|---|---|
lt | < | Less than |
gt | > | Greater than |
gteq | >= | Greater than or equal to |
lteq | <= | Less than or equal to |
eq | = | Equal to |
neq | != | Not equal to |
like | LIKE | Similar to |
is | IS | is |
is not | IS NOT | is not |
in | IN | Is in (set) |
notin | NOT IN | Is not in (set) |
Multiple operators
can be passed to for a single column
like:
{'created_at' => {'gt' => '1 day ago', 'lt' => '1 hour ago'}}
There’s also a shorcut to ‘eq’ by eliminating the operator
:
{'name' => 'Programming Ruby'}
is equivilent to:
{'name' => {'eq' => 'Programming Ruby'}}
A value
is a string passed evaluated in the ActiveRecord conditions array. In the case of Date and Time like objects, Restful Query can make use of the chronic
gem to parse string representations of time like those written about above. This solves for a lot of the inconsitancis between different languages/classes/apps representations of time as a string. If you pass :chronic => true
to can_query
the parser will automaticaly interpret the created_at
and updated_at
columns through chronic. If there are differnt columns you wish to interpret through chronic pass them in an array to :chronic
in can_query
. e.g:
class Book < ActiveRecord::Base
can_query :chronic => ['last_viewed_at', :updated_at]
end
For ‘special values’ you can also pass a symbol-like string to ensure the value is converted to a literal.
:true | true |
:false | false |
:nil | nil |
:null | nil |
Restful Query also provides the ability to sort/order results by passing a _sort
key to the restful_query
named_scope. _sort
takes an array of strings with a simple but specific format of:
column-direction
Where direction is one of:
- asc
- desc
- up
- down
For example:
{'created_at' => {'gt' => '1 day ago'}, '_sort' => 'created_at-desc'}
or with multiple:
{'created_at' => {'gt' => '1 day ago'}, '_sort' => ['created_at-desc', 'name-asc']}
You can aslo pass a :default_sort
option to can_query
using the format above.
Implementing Restful Query in a resource index super simple. First, include the macro in the model, then in the controller:
class BooksController < ApplicationController
def index
@books = Book.restful_query(params[:query]).paginate(:page => (params[:page] || 1), :per_page => 20)
respond_to do |format|
format.html
format.xml { render :xml => @books}
end
end
...
end
Since restful_query
is just a named_scope it can be chained with other find/scope operations as with will_paginate’s paginate
above.
Restful Query is also used to great effect in another gem o’ mine: qadmin
Dependencies
- rubygems >= 1.3.1
- chronic >= 0.2.3
- activesupport >= 2.2.0
Installing
sudo gem install restful_query
Or directly from github:
sudo gem install quirkey-restful_query -s http://gems.github.com
You can also install it as a rails plugin:
./script/plugin install git://github.com/quirkey/restful_query.git
Github in thier infinite awesomeness also lets you download the source in multiple formats.
Bugs/Feature Requests
The full and most up to date source is at github:
http://github.com/quirkey/restful_query/
You can clone or fork from there to fix or break the code.
I’m happy to take feature requests/bug reports. Just email me (contact below) or message me on github.
License
This code is free to use under the terms of the MIT license.
Contact
Feel free to email me at aaron at quirkey dot com.
Please check out my blog.
If you like or use this library – I don’t want donations – but you can recommend me on workingwithrails.com or hire me to work on your next project.