Module: Sinatra::API::Helpers

Defined in:
lib/algol/sinatra/api_helpers.rb

Instance Method Summary collapse

Instance Method Details

#__api_locate_resource(r, container = nil) ⇒ Object

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.

Examples:

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


144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# 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

#api_call?Boolean

Returns:

  • (Boolean)


6
7
8
# File 'lib/algol/sinatra/api_helpers.rb', line 6

def api_call?
  (request.accept || '').to_s.include?('json')
end

#api_clear!Object Also known as: api_reset!



118
119
120
# File 'lib/algol/sinatra/api_helpers.rb', line 118

def api_clear!()
  @api = { required: {}, optional: {} }
end

#api_consume!(keys) ⇒ Object

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


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# 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

#api_has_param?(key) ⇒ Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/algol/sinatra/api_helpers.rb', line 100

def api_has_param?(key)
  @api[:optional].has_key?(key)
end

#api_optional!(args, h = params) ⇒ Object

Same as #api_required! except that fields defined in this map are optional and will be used only if they’re supplied.

See Also:



50
51
52
53
54
55
56
57
58
59
# 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

#api_param(key) ⇒ Object



104
105
106
# File 'lib/algol/sinatra/api_helpers.rb', line 104

def api_param(key)
  @api[:optional][key.to_sym] || @api[:required][key.to_sym]
end

#api_params(q = {}) ⇒ Object

Returns a Hash of the supplied request parameters. Rejects any parameter that was not defined in the REQUIRED or OPTIONAL maps (or was consumed).

Parameters:

  • Hash

    q A Hash of attributes to merge with the parameters, useful for defining defaults



114
115
116
# File 'lib/algol/sinatra/api_helpers.rb', line 114

def api_params(q = {})
  @api[:optional].deep_merge(@api[:required]).deep_merge(q)
end

#api_required!(args, h = params) ⇒ Object

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!

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.

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.

Examples:

A map of required API call arguments

api_required!({ title: nil, user_id: nil })

Rejecting a title if it’s rude

api_required!({
  :title => lambda { |t| return "Don't be rude" if t && t =~ /rude/ }
})


35
36
37
38
39
40
41
42
43
44
# 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

#api_transform!(key, &handler) ⇒ Object



90
91
92
93
94
95
96
97
98
# 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