class Grape::API::Instance
The API
Instance
class, is the engine behind Grape::API
. Each class that inherits from this will represent a different API
instance
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
Source
# File lib/grape/api/instance.rb, line 23 def base=(grape_api) @base = grape_api grape_api.instances << self end
Source
# File lib/grape/api/instance.rb, line 32 def base_instance? self == base.base_instance end
Source
# File lib/grape/api/instance.rb, line 62 def call(env) compile! call!(env) end
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.
Source
# File lib/grape/api/instance.rb, line 68 def call!(env) instance.call(env) end
A non-synchronized version of ::call
.
Source
# File lib/grape/api/instance.rb, line 73 def cascade(value = nil) if value.nil? inheritable_setting.namespace_inheritable.key?(:cascade) ? !namespace_inheritable(:cascade).nil? : true else namespace_inheritable(:cascade, value) end end
(see cascade?
)
Source
# File lib/grape/api/instance.rb, line 54 def change! @instance = nil end
Wipe the compiled API
so we can recompile after changes were made.
Source
# File lib/grape/api/instance.rb, line 49 def compile @instance ||= new # rubocop:disable Naming/MemoizedInstanceVariableName end
Parses the API’s definition and compiles it into an instance of Grape::API
.
Source
# File lib/grape/api/instance.rb, line 81 def compile! return if instance LOCK.synchronize { compile unless instance } end
Source
# File lib/grape/api/instance.rb, line 15 def given(conditional_option, &block) evaluate_as_instance_with_configuration(block, lazy: true) if conditional_option && block end
Source
# File lib/grape/api/instance.rb, line 19 def mounted(&block) evaluate_as_instance_with_configuration(block, lazy: true) end
Source
# File lib/grape/api/instance.rb, line 152 def initialize @router = Router.new add_head_not_allowed_methods_and_options_methods self.class.endpoints.each do |endpoint| endpoint.mount_in(@router) end @router.compile! @router.freeze end
Builds the routes from the defined endpoints, effectively compiling this API
into a usable form.
Source
# File lib/grape/api/instance.rb, line 88 def recognize_path(path) compile! instance.router.recognize_path(path) end
Source
# File lib/grape/api/instance.rb, line 41 def reset! reset_endpoints! reset_routes! reset_validations! end
Clears all defined routes, endpoints, etc., on this API
.
Source
# File lib/grape/api/instance.rb, line 28 def to_s base&.to_s || super end
Protected Class Methods
Source
# File lib/grape/api/instance.rb, line 113 def evaluate_as_instance_with_configuration(block, lazy: false) lazy_block = Grape::Util::Lazy::Block.new do |configuration| value_for_configuration = configuration self.configuration = value_for_configuration.evaluate if value_for_configuration.try(:lazy?) response = instance_eval(&block) self.configuration = value_for_configuration response end if base && base_instance? && lazy lazy_block else lazy_block.evaluate_from(configuration) end end
Source
# File lib/grape/api/instance.rb, line 134 def inherit_settings(other_settings) top_level_setting.inherit_from other_settings.point_in_time_copy # Propagate any inherited params down to our endpoints, and reset any # compiled routes. endpoints.each do |e| e.inherit_settings(top_level_setting.namespace_stackable) e.reset_routes! end reset_routes! end
Source
# File lib/grape/api/instance.rb, line 128 def inherited(subclass) super subclass.reset! subclass.logger = logger.clone end
Source
# File lib/grape/api/instance.rb, line 102 def nest(*blocks, &block) blocks.compact! if blocks.any? evaluate_as_instance_with_configuration(block) if block blocks.each { |b| evaluate_as_instance_with_configuration(b) } reset_validations! else instance_eval(&block) end end
Execute first the provided block, then each of the block passed in. Allows for simple ‘before’ setups of settings stack pushes.
Source
# File lib/grape/api/instance.rb, line 95 def prepare_routes endpoints.map(&:routes).flatten end
Public Instance Methods
Source
# File lib/grape/api/instance.rb, line 164 def call(env) status, headers, response = @router.call(env) unless cascade? headers = Grape::Util::Header.new.merge(headers) headers.delete('X-Cascade') end [status, headers, response] end
Handle a request. See Rack documentation for what ‘env` is.
Source
# File lib/grape/api/instance.rb, line 182 def cascade? return self.class.namespace_inheritable(:cascade) if self.class.inheritable_setting.namespace_inheritable.key?(:cascade) return self.class.namespace_inheritable(:version_options)[:cascade] if self.class.namespace_inheritable(:version_options)&.key?(:cascade) true end
Some requests may return a HTTP 404 error if grape cannot find a matching route. In this case, Grape::Router
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.
Private Instance Methods
Source
# File lib/grape/api/instance.rb, line 197 def add_head_not_allowed_methods_and_options_methods # The paths we collected are prepared (cf. Path#prepare), so they # contain already versioning information when using path versioning. all_routes = self.class.endpoints.map(&:routes).flatten # Disable versioning so adding a route won't prepend versioning # informations again. without_root_prefix_and_versioning { collect_route_config_per_pattern(all_routes) } end
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.
Source
# File lib/grape/api/instance.rb, line 207 def collect_route_config_per_pattern(all_routes) routes_by_regexp = all_routes.group_by(&:pattern_regexp) # Build the configuration based on the first endpoint and the collection of methods supported. routes_by_regexp.each_value do |routes| last_route = routes.last # Most of the configuration is taken from the last endpoint next if routes.any? { |route| route.request_method == '*' } allowed_methods = routes.map(&:request_method) allowed_methods |= [Rack::HEAD] if !self.class.namespace_inheritable(:do_not_route_head) && allowed_methods.include?(Rack::GET) allow_header = self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Rack::OPTIONS] | allowed_methods last_route.app.options[:options_route_enabled] = true unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Rack::OPTIONS) @router.associate_routes(last_route.pattern, { endpoint: last_route.app, allow_header: allow_header }) end end
Source
# File lib/grape/api/instance.rb, line 230 def without_root_prefix_and_versioning old_version = self.class.namespace_inheritable(:version) old_version_options = self.class.namespace_inheritable(:version_options) old_root_prefix = self.class.namespace_inheritable(:root_prefix) self.class.namespace_inheritable_to_nil(:version) self.class.namespace_inheritable_to_nil(:version_options) self.class.namespace_inheritable_to_nil(:root_prefix) yield self.class.namespace_inheritable(:version, old_version) self.class.namespace_inheritable(:version_options, old_version_options) self.class.namespace_inheritable(:root_prefix, old_root_prefix) end
Allows definition of endpoints that ignore the versioning configuration used by the rest of your API
.