class Grape::API
should subclass this class in order to build an API.
The API class is the primary entry point for creating Grape APIs. Users
def add_setup(**step)
def add_setup(**step) @setup << step last_response = nil @instances.each do |instance| last_response = replay_step_on(instance, **step) end refresh_mount_step if step[:method] != :mount last_response end
def any_lazy?(args)
def any_lazy?(args) args.any?(Grape::Util::Lazy::Base) end
def configure
The configuration set here is accessible from inside an API with
API. If no block is given, returns the configuration hash.
configuration hash to the block which you can use to configure your
Configure an API from the outside. If a block is given, it'll pass a
def configure config = @base_instance.configuration return config unless block_given? yield config self end
def evaluate_arguments(configuration, *args)
def evaluate_arguments(configuration, *args) args.map do |argument| case argument when Grape::Util::Lazy::Base argument.evaluate_from(configuration) when Hash argument.transform_values { |value| evaluate_arguments(configuration, value).first } when Array evaluate_arguments(configuration, *argument) else argument end end end
def inherited(api)
When inherited, will create a list of all instances (times the API was mounted)
def inherited(api) super api.initial_setup(self == Grape::API ? Grape::API::Instance : @base_instance) api.override_all_methods! end
def initial_setup(base_instance_parent)
Initialize the instance variables on the remountable class, and the base_instance
def initial_setup(base_instance_parent) @instances = [] @setup = [] @base_parent = base_instance_parent @base_instance = mount_instance end
def mount_instance(configuration: nil)
depending on where the endpoint is mounted. Use with care, if you find yourself using configuration
For instance, a description could be done using: `desc configuration[:description]` if it may vary
The remountable class can have a configuration hash to provide some dynamic class-level variables.
def mount_instance(configuration: nil) instance = Class.new(@base_parent) instance.configuration = Grape::Util::EndpointConfiguration.new(configuration || {}) instance.base = self replay_setup_on(instance) instance end
def override_all_methods!
def override_all_methods! (base_instance.methods - Class.methods - NON_OVERRIDABLE).each do |method_override| define_singleton_method(method_override) do |*args, **kwargs, &block| add_setup(method: method_override, args:, kwargs:, block:) end end end
def refresh_mount_step
def refresh_mount_step @setup.each do |setup_step| next if setup_step[:method] != :mount refresh_mount_step = setup_step.merge(method: :refresh_mounted_api) @setup << refresh_mount_step @instances.each do |instance| replay_step_on(instance, **refresh_mount_step) end end end
def replay_setup_on(instance)
Replays the set up to produce an API as defined in this class, can be called
def replay_setup_on(instance) @setup.each do |setup_step| replay_step_on(instance, **setup_step) end end
def replay_step_on(instance, method:, args:, kwargs:, block:)
def replay_step_on(instance, method:, args:, kwargs:, block:) return if skip_immediate_run?(instance, args, kwargs) eval_args = evaluate_arguments(instance.configuration, *args) eval_kwargs = kwargs.deep_transform_values { |v| evaluate_arguments(instance.configuration, v).first } response = instance.__send__(method, *eval_args, **eval_kwargs, &block) return response if skip_immediate_run?(instance, [response], kwargs) evaluate_arguments(instance.configuration, response).first end
def skip_immediate_run?(instance, args, kwargs)
def skip_immediate_run?(instance, args, kwargs) instance.base_instance? && (any_lazy?(args) || args.any? { |arg| arg.is_a?(Hash) && any_lazy?(arg.values) } || any_lazy?(kwargs.values)) end