class Grape::API
The API class is the primary entry point for creating Grape APIs. Users should subclass this class in order to build an API.
Constants
- Boolean
- LOCK
A class-level lock to ensure the API is not compiled by multiple threads simultaneously within the same process.
Attributes
Public Class Methods
This is the interface point between Rack and Grape; it accepts a request from Rack and ultimately returns an array of three values: the status, the headers, and the body. See [the rack specification] (www.rubydoc.info/github/rack/rack/master/file/SPEC) for more.
# File lib/grape/api.rb, line 36 def call(env) LOCK.synchronize { compile } unless instance call!(env) end
A non-synchronized version of ::call.
# File lib/grape/api.rb, line 42 def call!(env) instance.call(env) end
(see cascade?)
# File lib/grape/api.rb, line 47 def cascade(value = nil) if value.nil? inheritable_setting.namespace_inheritable.keys.include?(:cascade) ? !namespace_inheritable(:cascade).nil? : true else namespace_inheritable(:cascade, value) end end
Wipe the compiled API so we can recompile after changes were made.
# File lib/grape/api.rb, line 28 def change! @instance = nil end
Parses the API's definition and compiles it into an instance of Grape::API.
# File lib/grape/api.rb, line 23 def compile @instance ||= new end
Builds the routes from the defined endpoints, effectively compiling this API into a usable form.
# File lib/grape/api.rb, line 89 def initialize @route_set = Rack::Mount::RouteSet.new add_head_not_allowed_methods_and_options_methods self.class.endpoints.each do |endpoint| endpoint.mount_in(@route_set) end @route_set.freeze end
Clears all defined routes, endpoints, etc., on this API.
# File lib/grape/api.rb, line 15 def reset! reset_endpoints! reset_routes! reset_validations! end
Protected Class Methods
# File lib/grape/api.rb, line 80 def inherit_settings(other_settings) top_level_setting.inherit_from other_settings.point_in_time_copy reset_routes! end
# File lib/grape/api.rb, line 75 def inherited(subclass) subclass.reset! subclass.logger = logger.clone end
Execute first the provided block, then each of the block passed in. Allows for simple 'before' setups of settings stack pushes.
# File lib/grape/api.rb, line 64 def nest(*blocks, &block) blocks.reject!(&:nil?) if blocks.any? instance_eval(&block) if block_given? blocks.each { |b| instance_eval(&b) } reset_validations! else instance_eval(&block) end end
# File lib/grape/api.rb, line 57 def prepare_routes endpoints.map(&:routes).flatten end
Public Instance Methods
Handle a request. See Rack documentation for what `env` is.
# File lib/grape/api.rb, line 100 def call(env) result = @route_set.call(env) result[1].delete(Grape::Http::Headers::X_CASCADE) unless cascade? result end
Some requests may return a HTTP 404 error if grape cannot find a matching route. In this case, Rack::Mount adds a X-Cascade header to the response and sets it to 'pass', indicating to grape's parents they should keep looking for a matching route on other resources.
In some applications (e.g. mounting grape on rails), one might need to trap errors from reaching upstream. This is effectivelly done by unsetting X-Cascade. Default :cascade is true.
# File lib/grape/api.rb, line 114 def cascade? return !!self.class.namespace_inheritable(:cascade) if self.class.inheritable_setting.namespace_inheritable.keys.include?(:cascade) return !!self.class.namespace_inheritable(:version_options)[:cascade] if self.class.namespace_inheritable(:version_options) && self.class.namespace_inheritable(:version_options).key?(:cascade) true end
Private Instance Methods
For every resource add a 'OPTIONS' route that returns an HTTP 204 response with a list of HTTP methods that can be called. Also add a route that will return an HTTP 405 response for any HTTP method that the resource cannot handle.
# File lib/grape/api.rb, line 128 def add_head_not_allowed_methods_and_options_methods methods_per_path = {} self.class.endpoints.each do |endpoint| routes = endpoint.routes routes.each do |route| route_path = route.route_path .gsub(/\(.*\)/, '') # ignore any optional portions .gsub(%r{\:[^\/.?]+}, ':x') # substitute variable names to avoid conflicts methods_per_path[route_path] ||= [] methods_per_path[route_path] << route.route_method # using the :any shorthand produces [nil] for route methods, substitute all manually methods_per_path[route_path] = %w(GET PUT POST DELETE PATCH HEAD OPTIONS) if methods_per_path[route_path].compact.empty? end end # The paths we collected are prepared (cf. Path#prepare), so they # contain already versioning information when using path versioning. # Disable versioning so adding a route won't prepend versioning # informations again. without_root_prefix do without_versioning do methods_per_path.each do |path, methods| allowed_methods = methods.dup unless self.class.namespace_inheritable(:do_not_route_head) allowed_methods |= [Grape::Http::Headers::HEAD] if allowed_methods.include?(Grape::Http::Headers::GET) end allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Grape::Http::Headers::OPTIONS] | allowed_methods).join(', ') unless self.class.namespace_inheritable(:do_not_route_options) generate_options_method(path, allow_header) unless allowed_methods.include?(Grape::Http::Headers::OPTIONS) end generate_not_allowed_method(path, allowed_methods, allow_header) end end end end
Generate a route that returns an HTTP 405 response for a user defined path on methods not specified
# File lib/grape/api.rb, line 182 def generate_not_allowed_method(path, allowed_methods, allow_header) not_allowed_methods = %w(GET PUT POST DELETE PATCH HEAD) - allowed_methods not_allowed_methods << Grape::Http::Headers::OPTIONS if self.class.namespace_inheritable(:do_not_route_options) return if not_allowed_methods.empty? self.class.route(not_allowed_methods, path) do fail Grape::Exceptions::MethodNotAllowed, header.merge('Allow' => allow_header) end end
Generate an 'OPTIONS' route for a pre-exisiting user defined route
# File lib/grape/api.rb, line 172 def generate_options_method(path, allow_header) self.class.options(path, {}) do header 'Allow', allow_header status 204 '' end end
Allows definition of endpoints that ignore the root prefix used by the rest of your API.
# File lib/grape/api.rb, line 210 def without_root_prefix(&_block) old_prefix = self.class.namespace_inheritable(:root_prefix) self.class.namespace_inheritable_to_nil(:root_prefix) yield self.class.namespace_inheritable(:root_prefix, old_prefix) end
Allows definition of endpoints that ignore the versioning configuration used by the rest of your API.
# File lib/grape/api.rb, line 195 def without_versioning(&_block) old_version = self.class.namespace_inheritable(:version) old_version_options = self.class.namespace_inheritable(:version_options) self.class.namespace_inheritable_to_nil(:version) self.class.namespace_inheritable_to_nil(:version_options) yield self.class.namespace_inheritable(:version, old_version) self.class.namespace_inheritable(:version_options, old_version_options) end