Created
March 7, 2011 07:03
-
-
Save patmaddox/858172 to your computer and use it in GitHub Desktop.
Wondering what people think. Gratuitous refactoring, or marvelous use of Ruby?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module API | |
class Version1 < Grape::API | |
version 'v1' | |
resource :hotels do | |
get '/' do | |
if [:latlng, :query].all? {|key| params[key].blank? } | |
error! 'Please pass in latlng|query' | |
end | |
response = {} | |
finder = Hotel | |
if query = params[:query] | |
response[:query] = query | |
finder = finder.search query | |
end | |
if latlng = params[:latlng] | |
latitude, longitude = latlng.split(',').map(&:to_f) | |
location = {:latitude => latitude, :longitude => longitude} | |
response[:location] = location | |
finder = finder.nearby location | |
end | |
response[:hotels] = finder | |
response | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module API | |
class Version1 < Grape::API | |
version 'v1' | |
helpers do | |
def hotels_response | |
@_method_collector = MethodCollector.new | |
@_queried_params = [] | |
response = {} | |
yield response | |
if !@_queried_params.empty? && @_queried_params.all? {|key| params[key].blank? } | |
error! "Please pass in #{@_queried_params.join('|')}" | |
end | |
response[:hotels] = @_method_collector.chain Hotel | |
response | |
end | |
def on_param(param_name) | |
@_queried_params << param_name | |
return if (value = params[param_name]).blank? | |
yield value, @_method_collector | |
end | |
end | |
resource :hotels do | |
get '/' do | |
hotels_response do |response| | |
on_param(:query) do |query, finder| | |
response[:query] = query | |
finder.search query | |
end | |
on_param(:latlng) do |latlng, finder| | |
latitude, longitude = latlng.split(',').map(&:to_f) | |
location = {:latitude => latitude, :longitude => longitude} | |
response[:location] = location | |
finder.nearby location | |
end | |
end | |
end | |
end | |
end | |
end | |
class MethodCollector | |
def initialize | |
@called_methods = [] | |
end | |
def method_missing(sym, *args, &block) | |
@called_methods << {:method => sym, :args => args, :block => block} | |
end | |
def chain(starting_point) | |
([starting_point] + @called_methods).inject {|finder, method_call| | |
finder.send(method_call[:method], *method_call[:args], &method_call[:block]) | |
} | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# I extended the previous code by adding a new 'show' action, as well as 404 handling | |
module API | |
class Version1 < Grape::API | |
version 'v1' | |
helpers do | |
def return_response(finder_key) | |
@_method_collector = MethodCollector.new | |
@_queried_params = [] | |
response = {} | |
yield response | |
if !@_queried_params.empty? && @_queried_params.all? {|key| params[key].blank? } | |
error! "Please pass in #{@_queried_params.join('|')}" | |
end | |
begin | |
response[finder_key] = @_method_collector.chain Hotel | |
rescue Mongoid::Errors::DocumentNotFound | |
error! "Not Found", 404 | |
end | |
response | |
end | |
def on_param(param_name) | |
@_queried_params << param_name | |
return if (value = params[param_name]).blank? | |
yield value, @_method_collector | |
end | |
end | |
resource :hotels do | |
get '/:id.json' do | |
return_response(:hotel) do |response| | |
on_param(:id) do |id, finder| | |
finder.find id | |
end | |
end | |
end | |
get '/' do | |
return_response(:hotels) do |response| | |
on_param(:query) do |query, finder| | |
response[:query] = query | |
finder.search query | |
end | |
on_param(:latlng) do |latlng, finder| | |
latitude, longitude = latlng.split(',').map(&:to_f) | |
location = {:latitude => latitude, :longitude => longitude} | |
response[:location] = location | |
finder.nearby location | |
end | |
end | |
end | |
end | |
end | |
end |
So the model methods are expected to be scopes, correct? They get chained together, and the on_param blocks, in a way, serve as a dsl to build AND queries. Do I have that right?
yeah so the point of this is to generate a JSON document to return to the API caller (web-based API). When they hit the index, they pass in some params...they need to pass in at least query OR latlng, and they can pass in both. So I need to support query on its own, latlng on its own, and the combo of query & latlng. More params are likely to come later too. Also if the param is missing, then I need to show an error.
Yeah the model methods are scopes that can be chained together (that's what MethodCollector#chain is doing)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very interesting. Intriguing, even. Seems like a nice, clean dsl for building publicly facing API's.