module Sinatra::API::Helpers
Public Instance Methods
Attempt to locate a resource based on an ID supplied in a request parameter.
If the param map contains a resource id (ie, :folder_id), we attempt to locate and expose it to the route.
A 404 is raised if:
1. the scope is missing (@space for folder, @space or @folder for page) 2. the resource couldn't be identified in its scope (@space or @folder)
If the resources were located, they’re accessible using @folder or @page.
The route can be halted using the :requires => [] condition when it expects a resource.
@example using :requires to reject a request with an invalid @page
get '/folders/:folder_id/pages/:page_id', :requires => [ :page ] do @page.show # page is good @folder.show # so is its folder end
# File lib/algol/sinatra/api_helpers.rb, line 144 def __api_locate_resource(r, container = nil) resource_id = params[r + '_id'].to_i rklass = r.capitalize collection = case when container.nil?; eval "#{rklass}" else; container.send("#{r.to_plural}") end # puts "locating resource #{r} with id #{resource_id} from #{collection} [#{container}]" resource = collection.get(resource_id) if !resource m = "No such resource: #{rklass}##{resource_id}" if container m << " in #{container.class.name.to_s}##{container.id}" end halt 404, m end unless can? :access, resource halt 403, "You do not have access to this #{rklass} resource." end instance_variable_set('@'+r, resource) resource end
# File lib/algol/sinatra/api_helpers.rb, line 6 def api_call? (request.accept || '').to_s.include?('json') end
# File lib/algol/sinatra/api_helpers.rb, line 118 def api_clear!() @api = { required: {}, optional: {} } end
Consumes supplied parameters with the given keys from the API
parameter map, and yields the consumed values for processing by the supplied block (if any).
This is useful if:
1. a certain parameter does not correspond to a model attribute and needs to be renamed, or is used in a validation context 2. the data needs special treatment 3. the data needs to be (re)formatted
# File lib/algol/sinatra/api_helpers.rb, line 71 def api_consume!(keys) out = nil keys = [ keys ] unless keys.is_a?(Array) keys.each do |k| if val = @api[:required].delete(k.to_sym) out = val out = yield(val) if block_given? end if val = @api[:optional].delete(k.to_sym) out = val out = yield(val) if block_given? end end out end
# File lib/algol/sinatra/api_helpers.rb, line 100 def api_has_param?(key) @api[:optional].has_key?(key) end
Same as api_required!
except that fields defined in this map are optional and will be used only if they’re supplied.
@see api_required!
# File lib/algol/sinatra/api_helpers.rb, line 50 def api_optional!(args, h = params) args.each_pair { |name, cnd| if cnd.is_a?(Hash) api_optional!(cnd, h[name]) next end parse_api_argument(h, name, cnd, :optional) } end
# File lib/algol/sinatra/api_helpers.rb, line 104 def api_param(key) @api[:optional][key.to_sym] || @api[:required][key.to_sym] end
Returns a Hash of the supplied request parameters. Rejects any parameter that was not defined in the REQUIRED or OPTIONAL maps (or was consumed).
@param Hash q A Hash of attributes to merge with the parameters,
useful for defining defaults
# File lib/algol/sinatra/api_helpers.rb, line 114 def api_params(q = {}) @api[:optional].deep_merge(@api[:required]).deep_merge(q) end
Define the required API
arguments map. Any item defined not found in the supplied parameters of the API
call will result in a 400 RC with a proper message marking the missing field.
The map is a Hash of parameter keys and optional validator blocks.
@example A map of required API
call arguments
api_required!({ title: nil, user_id: nil })
Each entry can be optionally mapped to a validation proc that will be invoked if the field was supplied. The proc will be passed the value of the field.
If the value is invalid and you need to suspend the request, you must return a String object with an appropriate error message.
@example Rejecting a title if it’s rude
api_required!({ :title => lambda { |t| return "Don't be rude" if t && t =~ /rude/ } })
@note
The supplied value passed to validation blocks is not pre-processed, so you must make sure that you check for nils or bad values in validator blocks!
# File lib/algol/sinatra/api_helpers.rb, line 35 def api_required!(args, h = params) args.each_pair { |name, cnd| if cnd.is_a?(Hash) api_required!(cnd, h[name]) next end parse_api_argument(h, name, cnd, :required) } end
# File lib/algol/sinatra/api_helpers.rb, line 90 def api_transform!(key, &handler) if val = @api[:required][key.to_sym] @api[:required][key.to_sym] = yield(val) if block_given? end if val = @api[:optional][key.to_sym] @api[:optional][key.to_sym] = yield(val) if block_given? end end
Private Instance Methods
# File lib/algol/sinatra/api_helpers.rb, line 178 def parse_api_argument(h = params, name, cnd, type) cnd ||= lambda { |*_| true } name = name.to_s unless [:required, :optional].include?(type) raise ArgumentError, 'API Argument type must be either :required or :optional' end if !h.has_key?(name) if type == :required halt 400, "Missing required parameter :#{name}" end else if cnd.respond_to?(:call) errmsg = cnd.call(h[name]) halt 400, { :"#{name}" => errmsg } if errmsg && errmsg.is_a?(String) end @api[type][name.to_sym] = h[name] end end