1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
# frozen_string_literal: true
require 'active_support/concern'
module Grape
module DSL
module RequestResponse
extend ActiveSupport::Concern
include Grape::DSL::Configuration
module ClassMethods
# Specify the default format for the API's serializers.
# May be `:json` or `:txt` (default).
def default_format(new_format = nil)
namespace_inheritable(:default_format, new_format.nil? ? nil : new_format.to_sym)
end
# Specify the format for the API's serializers.
# May be `:json`, `:xml`, `:txt`, etc.
def format(new_format = nil)
if new_format
namespace_inheritable(:format, new_format.to_sym)
# define the default error formatters
namespace_inheritable(:default_error_formatter, Grape::ErrorFormatter.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
namespace_stackable(:content_types, new_format.to_sym => mime_type)
else
namespace_inheritable(:format)
end
end
# Specify a custom formatter for a content-type.
def formatter(content_type, new_formatter)
namespace_stackable(:formatters, content_type.to_sym => new_formatter)
end
# Specify a custom parser for a content-type.
def parser(content_type, new_parser)
namespace_stackable(:parsers, content_type.to_sym => new_parser)
end
# Specify a default error formatter.
def default_error_formatter(new_formatter_name = nil)
if new_formatter_name
new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name, **{})
namespace_inheritable(:default_error_formatter, new_formatter)
else
namespace_inheritable(:default_error_formatter)
end
end
def error_formatter(format, options)
formatter = if options.is_a?(Hash) && options.key?(:with)
options[:with]
else
options
end
namespace_stackable(:error_formatters, format.to_sym => formatter)
end
# Specify additional content-types, e.g.:
# content_type :xls, 'application/vnd.ms-excel'
def content_type(key, val)
namespace_stackable(:content_types, key.to_sym => val)
end
# All available content types.
def content_types
c_types = namespace_stackable_with_hash(:content_types)
Grape::ContentTypes.content_types_for c_types
end
# Specify the default status code for errors.
def default_error_status(new_status = nil)
namespace_inheritable(:default_error_status, new_status)
end
# Allows you to rescue certain exceptions that occur to return
# a grape error rather than raising all the way to the
# server level.
#
# @example Rescue from custom exceptions
# class ExampleAPI < Grape::API
# class CustomError < StandardError; end
#
# rescue_from CustomError
# end
#
# @overload rescue_from(*exception_classes, **options)
# @param [Array] exception_classes A list of classes that you want to rescue, or
# the symbol :all to rescue from all exceptions.
# @param [Block] block Execution block to handle the given exception.
# @param [Hash] options Options for the rescue usage.
# @option options [Boolean] :backtrace Include a backtrace in the rescue response.
# @option options [Boolean] :rescue_subclasses Also rescue subclasses of exception classes
# @param [Proc] handler Execution proc to handle the given exception as an
# alternative to passing a block.
def rescue_from(*args, &block)
if args.last.is_a?(Proc)
handler = args.pop
elsif block
handler = block
end
options = args.extract_options!
raise ArgumentError, 'both :with option and block cannot be passed' if block && options.key?(:with)
handler ||= extract_with(options)
if args.include?(:all)
namespace_inheritable(:rescue_all, true)
namespace_inheritable :all_rescue_handler, handler
elsif args.include?(:grape_exceptions)
namespace_inheritable(:rescue_all, true)
namespace_inheritable(:rescue_grape_exceptions, true)
else
handler_type =
case options[:rescue_subclasses]
when nil, true
:rescue_handlers
else
:base_only_rescue_handlers
end
namespace_reverse_stackable handler_type, args.map { |arg| [arg, handler] }.to_h
end
namespace_stackable(:rescue_options, options)
end
# 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.
#
# @example
# class ExampleAPI < Grape::API
# represent User, with: Entity::User
#
# get '/me' do
# present current_user # with: Entity::User is assumed
# end
# end
#
# 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.
#
# @param model_class [Class] The model class that will be represented.
# @option options [Class] :with The entity class that will represent the model.
def represent(model_class, options)
raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless options[:with].is_a?(Class)
namespace_stackable(:representations, model_class => options[:with])
end
private
def extract_with(options)
return unless options.key?(:with)
with_option = options.delete(:with)
return with_option if with_option.instance_of?(Proc)
return with_option.to_sym if with_option.instance_of?(Symbol) || with_option.instance_of?(String)
raise ArgumentError, "with: #{with_option.class}, expected Symbol, String or Proc"
end
end
end
end
end
|