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

NON_OVERRIDABLE

Class methods that we want to call on the API rather than on the API object

Attributes

base_instance[RW]
instances[RW]

Public Class Methods

call(...) click to toggle source

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. NOTE: This will only be called on an API directly mounted on RACK

# File lib/grape/api.rb, line 77
def call(...)
  instance_for_rack.call(...)
end
compile!() click to toggle source
# File lib/grape/api.rb, line 127
def compile!
  instance_for_rack.compile! # See API::Instance.compile!
end
configure() { |config| ... } click to toggle source

Configure an API from the outside. If a block is given, it’ll pass a configuration hash to the block which you can use to configure your API. If no block is given, returns the configuration hash. The configuration set here is accessible from inside an API with ‘configuration` as normal.

# File lib/grape/api.rb, line 62
def configure
  config = @base_instance.configuration
  if block_given?
    yield config
    self
  else
    config
  end
end
const_missing(*args) click to toggle source

Alleviates problems with autoloading by tring to search for the constant

Calls superclass method
# File lib/grape/api.rb, line 82
def const_missing(*args)
  if base_instance.const_defined?(*args)
    base_instance.const_get(*args)
  else
    super
  end
end
inherited(api) click to toggle source

When inherited, will create a list of all instances (times the API was mounted) It will listen to the setup required to mount that endpoint, and replicate it on any new instance

Calls superclass method
# File lib/grape/api.rb, line 32
def inherited(api)
  super

  api.initial_setup(self == Grape::API ? Grape::API::Instance : @base_instance)
  api.override_all_methods!
end
initial_setup(base_instance_parent) click to toggle source

Initialize the instance variables on the remountable class, and the base_instance an instance that will be used to create the set up but will not be mounted

# File lib/grape/api.rb, line 41
def initial_setup(base_instance_parent)
  @instances = []
  @setup = Set.new
  @base_parent = base_instance_parent
  @base_instance = mount_instance
end
method_missing(method, *args, &block) click to toggle source
Calls superclass method
# File lib/grape/api.rb, line 118
def method_missing(method, *args, &block)
  # If there's a missing method, it may be defined on the base_instance instead.
  if respond_to_missing?(method)
    base_instance.send(method, *args, &block)
  else
    super
  end
end
mount_instance(**opts) click to toggle source

The remountable class can have a configuration hash to provide some dynamic class-level variables. For instance, a description could be done using: ‘desc configuration` if it may vary depending on where the endpoint is mounted. Use with care, if you find yourself using configuration too much, you may actually want to provide a new API rather than remount it.

# File lib/grape/api.rb, line 94
def mount_instance(**opts)
  instance = Class.new(@base_parent)
  instance.configuration = Grape::Util::EndpointConfiguration.new(opts[:configuration] || {})
  instance.base = self
  replay_setup_on(instance)
  instance
end
new(...) click to toggle source

Rather than initializing an object of type Grape::API, create an object of type Instance

# File lib/grape/api.rb, line 26
def new(...)
  base_instance.new(...)
end
override_all_methods!() click to toggle source

Redefines all methods so that are forwarded to add_setup and be recorded

# File lib/grape/api.rb, line 49
def override_all_methods!
  (base_instance.methods - Class.methods - NON_OVERRIDABLE).each do |method_override|
    define_singleton_method(method_override) do |*args, &block|
      add_setup(method_override, *args, &block)
    end
  end
end
replay_setup_on(instance) click to toggle source

Replays the set up to produce an API as defined in this class, can be called on classes that inherit from Grape::API

# File lib/grape/api.rb, line 104
def replay_setup_on(instance)
  @setup.each do |setup_step|
    replay_step_on(instance, setup_step)
  end
end
respond_to?(method, include_private = false) click to toggle source
Calls superclass method
# File lib/grape/api.rb, line 110
def respond_to?(method, include_private = false)
  super || base_instance.respond_to?(method, include_private)
end
respond_to_missing?(method, include_private = false) click to toggle source
# File lib/grape/api.rb, line 114
def respond_to_missing?(method, include_private = false)
  base_instance.respond_to?(method, include_private)
end

Private Class Methods

add_setup(method, *args, &block) click to toggle source

Adds a new stage to the set up require to get a Grape::API up and running

# File lib/grape/api.rb, line 142
def add_setup(method, *args, &block)
  setup_step = { method: method, args: args, block: block }
  @setup += [setup_step]
  last_response = nil
  @instances.each do |instance|
    last_response = replay_step_on(instance, setup_step)
  end

  # Updating all previously mounted classes in the case that new methods have been executed.
  if method != :mount && @setup.any?
    previous_mount_steps = @setup.select { |step| step[:method] == :mount }
    previous_mount_steps.each do |mount_step|
      refresh_mount_step = mount_step.merge(method: :refresh_mounted_api)
      @setup += [refresh_mount_step]
      @instances.each do |instance|
        replay_step_on(instance, refresh_mount_step)
      end
    end
  end

  last_response
end
any_lazy?(args) click to toggle source
# File lib/grape/api.rb, line 183
def any_lazy?(args)
  args.any? { |argument| argument.respond_to?(:lazy?) && argument.lazy? }
end
evaluate_arguments(configuration, *args) click to toggle source
# File lib/grape/api.rb, line 187
def evaluate_arguments(configuration, *args)
  args.map do |argument|
    if argument.respond_to?(:lazy?) && argument.lazy?
      argument.evaluate_from(configuration)
    elsif argument.is_a?(Hash)
      argument.transform_values { |value| evaluate_arguments(configuration, value).first }
    elsif argument.is_a?(Array)
      evaluate_arguments(configuration, *argument)
    else
      argument
    end
  end
end
instance_for_rack() click to toggle source
# File lib/grape/api.rb, line 133
def instance_for_rack
  if never_mounted?
    base_instance
  else
    mounted_instances.first
  end
end
mounted_instances() click to toggle source
# File lib/grape/api.rb, line 205
def mounted_instances
  instances - [base_instance]
end
never_mounted?() click to toggle source
# File lib/grape/api.rb, line 201
def never_mounted?
  mounted_instances.empty?
end
replay_step_on(instance, setup_step) click to toggle source
# File lib/grape/api.rb, line 165
def replay_step_on(instance, setup_step)
  return if skip_immediate_run?(instance, setup_step[:args])

  args = evaluate_arguments(instance.configuration, *setup_step[:args])
  response = instance.send(setup_step[:method], *args, &setup_step[:block])
  if skip_immediate_run?(instance, [response])
    response
  else
    evaluate_arguments(instance.configuration, response).first
  end
end
skip_immediate_run?(instance, args) click to toggle source

Skips steps that contain arguments to be lazily executed (on re-mount time)

# File lib/grape/api.rb, line 178
def skip_immediate_run?(instance, args)
  instance.base_instance? &&
    (any_lazy?(args) || args.any? { |arg| arg.is_a?(Hash) && any_lazy?(arg.values) })
end