Class: Grape::API

Inherits:
Object
  • Object
show all
Extended by:
Validations::ClassMethods
Defined in:
lib/grape/api.rb,
lib/grape/validations/coerce.rb

Overview

The API class is the primary entry point for creating Grape APIs.Users should subclass this class in order to build an API.

Constant Summary collapse

Boolean =

rubocop:disable ConstantName

Virtus::Attribute::Boolean

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Validations::ClassMethods

document_attribute, params, reset_validations!

Constructor Details

#initializeAPI

Returns a new instance of API.



515
516
517
518
519
520
521
522
# File 'lib/grape/api.rb', line 515

def initialize
  @route_set = Rack::Mount::RouteSet.new
  self.class.endpoints.each do |endpoint|
    endpoint.mount_in(@route_set)
  end
  add_head_not_allowed_methods
  @route_set.freeze
end

Class Attribute Details

.endpointsObject (readonly)

Returns the value of attribute endpoints.



9
10
11
# File 'lib/grape/api.rb', line 9

def endpoints
  @endpoints
end

.instanceObject (readonly)

Returns the value of attribute instance.



9
10
11
# File 'lib/grape/api.rb', line 9

def instance
  @instance
end

.logger(logger = nil) ⇒ Object



12
13
14
15
16
17
18
# File 'lib/grape/api.rb', line 12

def logger(logger = nil)
  if logger
    @logger = logger
  else
    @logger ||= Logger.new($stdout)
  end
end

.route_setObject (readonly)

Returns the value of attribute route_set.



9
10
11
# File 'lib/grape/api.rb', line 9

def route_set
  @route_set
end

.routesObject (readonly)

An array of API routes.



459
460
461
# File 'lib/grape/api.rb', line 459

def routes
  @routes
end

.settingsObject (readonly)

Returns the value of attribute settings.



9
10
11
# File 'lib/grape/api.rb', line 9

def settings
  @settings
end

.versionsObject (readonly)

Returns the value of attribute versions.



9
10
11
# File 'lib/grape/api.rb', line 9

def versions
  @versions
end

Class Method Details

.after(&block) ⇒ Object



367
368
369
# File 'lib/grape/api.rb', line 367

def after(&block)
  imbue(:afters, [block])
end

.after_validation(&block) ⇒ Object



363
364
365
# File 'lib/grape/api.rb', line 363

def after_validation(&block)
  imbue(:after_validations, [block])
end

.auth(type = nil, options = {}, &block) ⇒ Object

Add an authentication type to the API. Currently only :http_basic, :http_digest and :oauth2 are supported.



295
296
297
298
299
300
301
# File 'lib/grape/api.rb', line 295

def auth(type = nil, options = {}, &block)
  if type
    set(:auth, { type: type.to_sym, proc: block }.merge(options))
  else
    settings[:auth]
  end
end

.before(&block) ⇒ Object



359
360
361
# File 'lib/grape/api.rb', line 359

def before(&block)
  imbue(:befores, [block])
end

.call(env) ⇒ Object



36
37
38
39
# File 'lib/grape/api.rb', line 36

def call(env)
  compile unless instance
  call!(env)
end

.call!(env) ⇒ Object



41
42
43
# File 'lib/grape/api.rb', line 41

def call!(env)
  instance.call(env)
end

.cascade(value = nil) ⇒ Object



467
468
469
470
471
472
473
# File 'lib/grape/api.rb', line 467

def cascade(value = nil)
  if value.nil?
    settings.has_key?(:cascade) ? !!settings[:cascade] : true
  else
    set(:cascade, value)
  end
end

.change!Object



32
33
34
# File 'lib/grape/api.rb', line 32

def change!
  @instance = nil
end

.compileObject



28
29
30
# File 'lib/grape/api.rb', line 28

def compile
  @instance = new
end

.content_type(key, val) ⇒ Object

Specify additional content-types, e.g.: content_type :xls, 'application/vnd.ms-excel'



171
172
173
# File 'lib/grape/api.rb', line 171

def content_type(key, val)
  settings.imbue(:content_types, key.to_sym => val)
end

.content_typesObject

All available content types.



176
177
178
# File 'lib/grape/api.rb', line 176

def content_types
  Grape::ContentTypes.content_types_for(settings[:content_types])
end

.default_error_formatter(new_formatter_name = nil) ⇒ Object

Specify a default error formatter.



150
151
152
153
154
155
156
157
# File 'lib/grape/api.rb', line 150

def default_error_formatter(new_formatter_name = nil)
  if new_formatter_name
    new_formatter = Grape::ErrorFormatter::Base.formatter_for(new_formatter_name, {})
    set(:default_error_formatter, new_formatter)
  else
    settings[:default_error_formatter]
  end
end

.default_error_status(new_status = nil) ⇒ Object

Specify the default status code for errors.



181
182
183
# File 'lib/grape/api.rb', line 181

def default_error_status(new_status = nil)
  new_status ? set(:default_error_status, new_status) : settings[:default_error_status]
end

.default_format(new_format = nil) ⇒ Object

Specify the default format for the API's serializers. May be :json or :txt (default).



119
120
121
# File 'lib/grape/api.rb', line 119

def default_format(new_format = nil)
  new_format ? set(:default_format, new_format.to_sym) : settings[:default_format]
end

.delete(paths = ['/'], options = {}, &block) ⇒ Object



387
388
389
# File 'lib/grape/api.rb', line 387

def delete(paths = ['/'], options = {}, &block)
  route('DELETE', paths, options, &block)
end

.desc(description, options = {}) ⇒ Object

Add a description to the next namespace or function.



113
114
115
# File 'lib/grape/api.rb', line 113

def desc(description, options = {})
  @last_description = options.merge(description: description)
end

.do_not_route_head!Object

Do not route HEAD requests to GET requests automatically



68
69
70
# File 'lib/grape/api.rb', line 68

def do_not_route_head!
  set(:do_not_route_head, true)
end

.do_not_route_options!Object

Do not automatically route OPTIONS



73
74
75
# File 'lib/grape/api.rb', line 73

def do_not_route_options!
  set(:do_not_route_options, true)
end

.error_formatter(format, options) ⇒ Object



159
160
161
162
163
164
165
166
167
# File 'lib/grape/api.rb', line 159

def error_formatter(format, options)
  if options.is_a?(Hash) && options.has_key?(:with)
    formatter = options[:with]
  else
    formatter = options
  end

  settings.imbue(:error_formatters, format.to_sym => formatter)
end

.format(new_format = nil) ⇒ Object

Specify the format for the API's serializers. May be :json, :xml, :txt, etc.



125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/grape/api.rb', line 125

def format(new_format = nil)
  if new_format
    set(:format, new_format.to_sym)
    # define the default error formatters
    set(:default_error_formatter, Grape::ErrorFormatter::Base.formatter_for(new_format, {}))
    # define a single mime type
    mime_type = content_types[new_format.to_sym]
    raise Grape::Exceptions::MissingMimeType.new(new_format) unless mime_type
    settings.imbue(:content_types, new_format.to_sym => mime_type)
  else
    settings[:format]
  end
end

.formatter(content_type, new_formatter) ⇒ Object

Specify a custom formatter for a content-type.



140
141
142
# File 'lib/grape/api.rb', line 140

def formatter(content_type, new_formatter)
  settings.imbue(:formatters, content_type.to_sym => new_formatter)
end

.get(paths = ['/'], options = {}, &block) ⇒ Object



371
372
373
# File 'lib/grape/api.rb', line 371

def get(paths = ['/'], options = {}, &block)
  route('GET', paths, options, &block)
end

.head(paths = ['/'], options = {}, &block) ⇒ Object



383
384
385
# File 'lib/grape/api.rb', line 383

def head(paths = ['/'], options = {}, &block)
  route('HEAD', paths, options, &block)
end

.helpers(new_mod = nil, &block) ⇒ Object

Add helper methods that will be accessible from any endpoint within this namespace (and child namespaces).

When called without a block, all known helpers within this scope are included.

Examples:

Define some helpers.


class ExampleAPI < Grape::API
  helpers do
    def current_user
      User.find_by_id(params[:token])
    end
  end
end

Parameters:

  • new_mod (Module) (defaults to: nil)

    optional module of methods to include

  • block (Block)

    optional block of methods to include



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/grape/api.rb', line 273

def helpers(new_mod = nil, &block)
  if block_given? || new_mod
    mod = settings.peek[:helpers] || Module.new
    if new_mod
      mod.class_eval do
        include new_mod
      end
    end
    mod.class_eval(&block) if block_given?
    set(:helpers, mod)
  else
    mod = Module.new
    settings.stack.each do |s|
      mod.send :include, s[:helpers] if s[:helpers]
    end
    change!
    mod
  end
end

.http_basic(options = {}, &block) ⇒ Object

Add HTTP Basic authorization to the API.

Parameters:

  • options (Hash) (defaults to: {})

    A hash of options.

Options Hash (options):

  • :realm (String)

    "API Authorization" The HTTP Basic realm.



307
308
309
310
# File 'lib/grape/api.rb', line 307

def http_basic(options = {}, &block)
  options[:realm] ||= "API Authorization"
  auth :http_basic, options, &block
end

.http_digest(options = {}, &block) ⇒ Object



312
313
314
315
316
# File 'lib/grape/api.rb', line 312

def http_digest(options = {}, &block)
  options[:realm] ||= "API Authorization"
  options[:opaque] ||= "secret"
  auth :http_digest, options, &block
end

.imbue(key, value) ⇒ Object

Add to a configuration value for this namespace.

Parameters:

  • key (Symbol)

    The key of the configuration variable.

  • value (Object)

    The value to which to set the configuration variable.



58
59
60
# File 'lib/grape/api.rb', line 58

def imbue(key, value)
  settings.imbue(key, value)
end

.middlewareObject

Retrieve an array of the middleware classes and arguments that are currently applied to the application.



451
452
453
454
455
456
# File 'lib/grape/api.rb', line 451

def middleware
  settings.stack.inject([]) do |a, s|
    a += s[:middleware] if s[:middleware]
    a
  end
end

.mount(mounts) ⇒ Object



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/grape/api.rb', line 318

def mount(mounts)
  mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair)
  mounts.each_pair do |app, path|
    if app.respond_to?(:inherit_settings, true)
      app_settings = settings.clone
      mount_path = Rack::Mount::Utils.normalize_path([settings[:mount_path], path].compact.join("/"))
      app_settings.set :mount_path, mount_path
      app.inherit_settings(app_settings)
    end
    endpoints << Grape::Endpoint.new(settings.clone, {
      method: :any,
      path: path,
      app: app
    })
  end
end

.namespace(space = nil, options = {}, &block) ⇒ Object Also known as: group, resource, resources, segment



399
400
401
402
403
404
405
406
407
408
409
410
411
# File 'lib/grape/api.rb', line 399

def namespace(space = nil, options = {},  &block)
  if space || block_given?
    previous_namespace_description = @namespace_description
    @namespace_description = (@namespace_description || {}).deep_merge(@last_description || {})
    @last_description = nil
    nest(block) do
      set(:namespace, Namespace.new(space, options)) if space
    end
    @namespace_description = previous_namespace_description
  else
    Namespace.joined_space_path(settings)
  end
end

.options(paths = ['/'], options = {}, &block) ⇒ Object



391
392
393
# File 'lib/grape/api.rb', line 391

def options(paths = ['/'], options = {}, &block)
  route('OPTIONS', paths, options, &block)
end

.parser(content_type, new_parser) ⇒ Object

Specify a custom parser for a content-type.



145
146
147
# File 'lib/grape/api.rb', line 145

def parser(content_type, new_parser)
  settings.imbue(:parsers, content_type.to_sym => new_parser)
end

.patch(paths = ['/'], options = {}, &block) ⇒ Object



395
396
397
# File 'lib/grape/api.rb', line 395

def patch(paths = ['/'], options = {}, &block)
  route('PATCH', paths, options, &block)
end

.post(paths = ['/'], options = {}, &block) ⇒ Object



375
376
377
# File 'lib/grape/api.rb', line 375

def post(paths = ['/'], options = {}, &block)
  route('POST', paths, options, &block)
end

.prefix(prefix = nil) ⇒ Object

Define a root URL prefix for your entire API.



63
64
65
# File 'lib/grape/api.rb', line 63

def prefix(prefix = nil)
  prefix ? set(:root_prefix, prefix) : settings[:root_prefix]
end

.put(paths = ['/'], options = {}, &block) ⇒ Object



379
380
381
# File 'lib/grape/api.rb', line 379

def put(paths = ['/'], options = {}, &block)
  route('PUT', paths, options, &block)
end

.represent(model_class, options) ⇒ Object

Allows you to specify a default representation entity for a class. This allows you to map your models to their respective entities once and then simply call present with the model.

Note that Grape will automatically go up the class ancestry to try to find a representing entity, so if you, for example, define an entity to represent Object then all presented objects will bubble up and utilize the entity provided on that represent call.

Examples:

class ExampleAPI < Grape::API
  represent User, with: Entity::User

  get '/me' do
    present current_user # with: Entity::User is assumed
  end
end

Parameters:

  • model_class (Class)

    The model class that will be represented.

  • options (Hash)

    a customizable set of options

Options Hash (options):

  • :with (Class)

    The entity class that will represent the model.

Raises:



249
250
251
252
# File 'lib/grape/api.rb', line 249

def represent(model_class, options)
  raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless options[:with] && options[:with].is_a?(Class)
  imbue(:representations, model_class => options[:with])
end

.rescue_from(*exception_classes, options = {}) ⇒ Object

Allows you to rescue certain exceptions that occur to return a grape error rather than raising all the way to the server level.

Examples:

Rescue from custom exceptions

class ExampleAPI < Grape::API
  class CustomError < StandardError; end

  rescue_from CustomError
end

Parameters:

  • exception_classes (Array)

    A list of classes that you want to rescue, or the symbol :all to rescue from all exceptions.

  • block (Block)

    Execution block to handle the given exception.

  • options (Hash) (defaults to: {})

    Options for the rescue usage.

  • handler (Proc)

    Execution proc to handle the given exception as an alternative to passing a block

Options Hash (options):

  • :backtrace (Boolean)

    Include a backtrace in the rescue response.



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/grape/api.rb', line 204

def rescue_from(*args, &block)
  if args.last.is_a?(Proc)
    handler = args.pop
  elsif block_given?
    handler = block
  end

  options = args.last.is_a?(Hash) ? args.pop : {}
  handler ||= proc { options[:with] } if options.has_key?(:with)

  if handler
    args.each do |arg|
      imbue(:rescue_handlers, { arg => handler })
    end
  end

  imbue(:rescue_options, options)

  if args.include?(:all)
    set(:rescue_all, true)
  else
    imbue(:rescued_errors, args)
  end
end

.reset!Object



20
21
22
23
24
25
26
# File 'lib/grape/api.rb', line 20

def reset!
  @settings  = Grape::Util::HashStack.new
  @route_set = Rack::Mount::RouteSet.new
  @endpoints = []
  @routes = nil
  reset_validations!
end

.route(methods, paths = ['/'], route_options = {}, &block) ⇒ Object

Defines a route that will be recognized by the Grape API.

Examples:

Defining a basic route.

class MyAPI < Grape::API
  route(:any, '/hello') do
    {hello: 'world'}
  end
end

Parameters:

  • methods (HTTP Verb)

    One or more HTTP verbs that are accepted by this route. Set to :any if you want any verb to be accepted.

  • paths (String) (defaults to: ['/'])

    One or more strings representing the URL segment(s) for this route.



347
348
349
350
351
352
353
354
355
356
357
# File 'lib/grape/api.rb', line 347

def route(methods, paths = ['/'], route_options = {}, &block)
  endpoint_options = {
    method: methods,
    path: paths,
    route_options: (@namespace_description || {}).deep_merge(@last_description || {}).deep_merge(route_options || {})
  }
  endpoints << Grape::Endpoint.new(settings.clone, endpoint_options, &block)

  @last_description = nil
  reset_validations!
end

.route_param(param, options = {}, &block) ⇒ Object

Thie method allows you to quickly define a parameter route segment in your API.

Parameters:

  • param (Symbol)

    The name of the parameter you wish to declare.

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • You (Regexp)

    may supply a regular expression that the declared parameter must meet.



418
419
420
421
422
# File 'lib/grape/api.rb', line 418

def route_param(param, options = {}, &block)
  options = options.dup
  options[:requirements] = { param.to_sym => options[:requirements] } if options[:requirements].is_a?(Regexp)
  namespace(":#{param}", options, &block)
end

.scope(name = nil, &block) ⇒ Object

Create a scope without affecting the URL.

Parameters:

  • name (Symbol) (defaults to: nil)

    Purely placebo, just allows to to name the scope to make the code more readable.



432
433
434
# File 'lib/grape/api.rb', line 432

def scope(name = nil, &block)
  nest(block)
end

.set(key, value) ⇒ Object

Set a configuration value for this namespace.

Parameters:

  • key (Symbol)

    The key of the configuration variable.

  • value (Object)

    The value to which to set the configuration variable.



49
50
51
# File 'lib/grape/api.rb', line 49

def set(key, value)
  settings[key.to_sym] = value
end

.use(middleware_class, *args, &block) ⇒ Object

Apply a custom middleware to the API. Applies to the current namespace and any children, but not parents.

Parameters:

  • middleware_class (Class)

    The class of the middleware you'd like to inject.



442
443
444
445
446
# File 'lib/grape/api.rb', line 442

def use(middleware_class, *args, &block)
  arr = [middleware_class, *args]
  arr << block if block_given?
  imbue(:middleware, [arr])
end

.version(*args, &block) ⇒ Object

Specify an API version.

Examples:

API with legacy support.

class MyAPI < Grape::API
  version 'v2'

  get '/main' do
    {some: 'data'}
  end

  version 'v1' do
    get '/main' do
      {legacy: 'data'}
    end
  end
end


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/grape/api.rb', line 94

def version(*args, &block)
  if args.any?
    options = args.pop if args.last.is_a? Hash
    options ||= {}
    options = { using: :path }.merge(options)

    raise Grape::Exceptions::MissingVendorOption.new if options[:using] == :header && !options.has_key?(:vendor)

    @versions = versions | args
    nest(block) do
      set(:version, args)
      set(:version_options, options)
    end
  end

  @versions.last unless @versions.nil?
end

Instance Method Details

#call(env) ⇒ Object



524
525
526
527
528
# File 'lib/grape/api.rb', line 524

def call(env)
  status, headers, body = @route_set.call(env)
  headers.delete('X-Cascade') unless cascade?
  [status, headers, body]
end

#cascade?Boolean

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.

Returns:



538
539
540
541
542
# File 'lib/grape/api.rb', line 538

def cascade?
  return !!self.class.settings[:cascade] if self.class.settings.has_key?(:cascade)
  return !!self.class.settings[:version_options][:cascade] if self.class.settings[:version_options] && self.class.settings[:version_options].has_key?(:cascade)
  true
end