grape 0.1.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1167 -0
- data/CONTRIBUTING.md +156 -0
- data/LICENSE +1 -1
- data/README.md +4192 -0
- data/UPGRADING.md +1697 -0
- data/grape.gemspec +28 -105
- data/grape.png +0 -0
- data/lib/grape/api/helpers.rb +9 -0
- data/lib/grape/api/instance.rb +247 -0
- data/lib/grape/api.rb +158 -194
- data/lib/grape/content_types.rb +31 -0
- data/lib/grape/cookies.rb +50 -0
- data/lib/grape/dry_types.rb +10 -0
- data/lib/grape/dsl/api.rb +17 -0
- data/lib/grape/dsl/callbacks.rb +69 -0
- data/lib/grape/dsl/configuration.rb +15 -0
- data/lib/grape/dsl/desc.rb +124 -0
- data/lib/grape/dsl/headers.rb +21 -0
- data/lib/grape/dsl/helpers.rb +108 -0
- data/lib/grape/dsl/inside_route.rb +454 -0
- data/lib/grape/dsl/logger.rb +22 -0
- data/lib/grape/dsl/middleware.rb +54 -0
- data/lib/grape/dsl/parameters.rb +266 -0
- data/lib/grape/dsl/request_response.rb +171 -0
- data/lib/grape/dsl/routing.rb +248 -0
- data/lib/grape/dsl/settings.rb +179 -0
- data/lib/grape/dsl/validations.rb +57 -0
- data/lib/grape/endpoint.rb +398 -68
- data/lib/grape/env.rb +20 -0
- data/lib/grape/error_formatter/base.rb +68 -0
- data/lib/grape/error_formatter/json.rb +28 -0
- data/lib/grape/error_formatter/serializable_hash.rb +7 -0
- data/lib/grape/error_formatter/txt.rb +21 -0
- data/lib/grape/error_formatter/xml.rb +11 -0
- data/lib/grape/error_formatter.rb +15 -0
- data/lib/grape/exceptions/base.rb +76 -0
- data/lib/grape/exceptions/conflicting_types.rb +11 -0
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/incompatible_option_values.rb +11 -0
- data/lib/grape/exceptions/invalid_accept_header.rb +11 -0
- data/lib/grape/exceptions/invalid_formatter.rb +11 -0
- data/lib/grape/exceptions/invalid_message_body.rb +11 -0
- data/lib/grape/exceptions/invalid_parameters.rb +11 -0
- data/lib/grape/exceptions/invalid_response.rb +11 -0
- data/lib/grape/exceptions/invalid_version_header.rb +11 -0
- data/lib/grape/exceptions/invalid_versioner_option.rb +11 -0
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +11 -0
- data/lib/grape/exceptions/method_not_allowed.rb +11 -0
- data/lib/grape/exceptions/missing_group_type.rb +13 -0
- data/lib/grape/exceptions/missing_mime_type.rb +11 -0
- data/lib/grape/exceptions/missing_option.rb +11 -0
- data/lib/grape/exceptions/missing_vendor_option.rb +11 -0
- data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
- data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
- data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
- data/lib/grape/exceptions/unknown_options.rb +11 -0
- data/lib/grape/exceptions/unknown_parameter.rb +11 -0
- data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
- data/lib/grape/exceptions/unknown_validator.rb +11 -0
- data/lib/grape/exceptions/unsupported_group_type.rb +13 -0
- data/lib/grape/exceptions/validation.rb +25 -0
- data/lib/grape/exceptions/validation_array_errors.rb +14 -0
- data/lib/grape/exceptions/validation_errors.rb +53 -0
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +24 -0
- data/lib/grape/extensions/hash.rb +27 -0
- data/lib/grape/extensions/hashie/mash.rb +24 -0
- data/lib/grape/formatter/base.rb +16 -0
- data/lib/grape/formatter/json.rb +13 -0
- data/lib/grape/formatter/serializable_hash.rb +39 -0
- data/lib/grape/formatter/txt.rb +11 -0
- data/lib/grape/formatter/xml.rb +13 -0
- data/lib/grape/formatter.rb +17 -0
- data/lib/grape/json.rb +10 -0
- data/lib/grape/locale/en.yml +59 -0
- data/lib/grape/middleware/auth/base.rb +23 -0
- data/lib/grape/middleware/auth/dsl.rb +39 -0
- data/lib/grape/middleware/auth/strategies.rb +25 -0
- data/lib/grape/middleware/auth/strategy_info.rb +15 -0
- data/lib/grape/middleware/base.rb +89 -18
- data/lib/grape/middleware/error.rb +129 -10
- data/lib/grape/middleware/filter.rb +19 -0
- data/lib/grape/middleware/formatter.rb +124 -82
- data/lib/grape/middleware/globals.rb +14 -0
- data/lib/grape/middleware/stack.rb +109 -0
- data/lib/grape/middleware/versioner/accept_version_header.rb +38 -0
- data/lib/grape/middleware/versioner/base.rb +74 -0
- data/lib/grape/middleware/versioner/header.rb +127 -0
- data/lib/grape/middleware/versioner/param.rb +32 -0
- data/lib/grape/middleware/versioner/path.rb +40 -0
- data/lib/grape/middleware/versioner.rb +21 -21
- data/lib/grape/namespace.rb +46 -0
- data/lib/grape/params_builder/base.rb +18 -0
- data/lib/grape/params_builder/hash.rb +11 -0
- data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
- data/lib/grape/params_builder/hashie_mash.rb +11 -0
- data/lib/grape/params_builder.rb +32 -0
- data/lib/grape/parser/base.rb +16 -0
- data/lib/grape/parser/json.rb +14 -0
- data/lib/grape/parser/xml.rb +14 -0
- data/lib/grape/parser.rb +15 -0
- data/lib/grape/path.rb +76 -0
- data/lib/grape/presenters/presenter.rb +11 -0
- data/lib/grape/railtie.rb +9 -0
- data/lib/grape/request.rb +190 -0
- data/lib/grape/router/base_route.rb +39 -0
- data/lib/grape/router/greedy_route.rb +20 -0
- data/lib/grape/router/pattern.rb +81 -0
- data/lib/grape/router/route.rb +62 -0
- data/lib/grape/router.rb +190 -0
- data/lib/grape/serve_stream/file_body.rb +36 -0
- data/lib/grape/serve_stream/sendfile_response.rb +21 -0
- data/lib/grape/serve_stream/stream_response.rb +23 -0
- data/lib/grape/types/invalid_value.rb +8 -0
- data/lib/grape/util/base_inheritable.rb +43 -0
- data/lib/grape/util/cache.rb +17 -0
- data/lib/grape/util/endpoint_configuration.rb +8 -0
- data/lib/grape/util/header.rb +13 -0
- data/lib/grape/util/inheritable_setting.rb +100 -0
- data/lib/grape/util/inheritable_values.rb +29 -0
- data/lib/grape/util/lazy/block.rb +29 -0
- data/lib/grape/util/lazy/value.rb +38 -0
- data/lib/grape/util/lazy/value_array.rb +21 -0
- data/lib/grape/util/lazy/value_enumerable.rb +34 -0
- data/lib/grape/util/lazy/value_hash.rb +21 -0
- data/lib/grape/util/media_type.rb +70 -0
- data/lib/grape/util/registry.rb +27 -0
- data/lib/grape/util/reverse_stackable_values.rb +15 -0
- data/lib/grape/util/stackable_values.rb +36 -0
- data/lib/grape/util/strict_hash_configuration.rb +108 -0
- data/lib/grape/validations/attributes_doc.rb +60 -0
- data/lib/grape/validations/attributes_iterator.rb +62 -0
- data/lib/grape/validations/contract_scope.rb +34 -0
- data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
- data/lib/grape/validations/params_scope.rb +538 -0
- data/lib/grape/validations/single_attribute_iterator.rb +26 -0
- data/lib/grape/validations/types/array_coercer.rb +61 -0
- data/lib/grape/validations/types/custom_type_coercer.rb +164 -0
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +56 -0
- data/lib/grape/validations/types/dry_type_coercer.rb +66 -0
- data/lib/grape/validations/types/file.rb +31 -0
- data/lib/grape/validations/types/invalid_value.rb +17 -0
- data/lib/grape/validations/types/json.rb +71 -0
- data/lib/grape/validations/types/multiple_type_coercer.rb +57 -0
- data/lib/grape/validations/types/primitive_coercer.rb +73 -0
- data/lib/grape/validations/types/set_coercer.rb +35 -0
- data/lib/grape/validations/types/variant_collection_coercer.rb +51 -0
- data/lib/grape/validations/types.rb +213 -0
- data/lib/grape/validations/validator_factory.rb +15 -0
- data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
- data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
- data/lib/grape/validations/validators/as_validator.rb +14 -0
- data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
- data/lib/grape/validations/validators/base.rb +88 -0
- data/lib/grape/validations/validators/coerce_validator.rb +75 -0
- data/lib/grape/validations/validators/contract_scope_validator.rb +41 -0
- data/lib/grape/validations/validators/default_validator.rb +37 -0
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
- data/lib/grape/validations/validators/except_values_validator.rb +24 -0
- data/lib/grape/validations/validators/length_validator.rb +49 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +34 -0
- data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
- data/lib/grape/validations/validators/presence_validator.rb +15 -0
- data/lib/grape/validations/validators/regexp_validator.rb +16 -0
- data/lib/grape/validations/validators/same_as_validator.rb +29 -0
- data/lib/grape/validations/validators/values_validator.rb +60 -0
- data/lib/grape/validations.rb +21 -0
- data/lib/grape/version.rb +6 -0
- data/lib/grape/xml.rb +10 -0
- data/lib/grape.rb +81 -17
- metadata +250 -192
- data/.document +0 -5
- data/.gitignore +0 -23
- data/.rspec +0 -2
- data/.rvmrc +0 -1
- data/Gemfile +0 -21
- data/Gemfile.lock +0 -58
- data/README.markdown +0 -75
- data/Rakefile +0 -70
- data/VERSION +0 -1
- data/autotest/discover.rb +0 -1
- data/lib/grape/middleware/auth/basic.rb +0 -30
- data/lib/grape/middleware/auth/oauth2.rb +0 -55
- data/lib/grape/middleware/prefixer.rb +0 -21
- data/lib/grape/middleware_stack.rb +0 -35
- data/spec/grape/api_spec.rb +0 -343
- data/spec/grape/endpoint_spec.rb +0 -104
- data/spec/grape/middleware/auth/basic_spec.rb +0 -31
- data/spec/grape/middleware/auth/oauth2_spec.rb +0 -88
- data/spec/grape/middleware/base_spec.rb +0 -63
- data/spec/grape/middleware/error_spec.rb +0 -49
- data/spec/grape/middleware/formatter_spec.rb +0 -87
- data/spec/grape/middleware/prefixer_spec.rb +0 -30
- data/spec/grape/middleware/versioner_spec.rb +0 -40
- data/spec/grape/middleware_stack_spec.rb +0 -47
- data/spec/grape_spec.rb +0 -1
- data/spec/spec_helper.rb +0 -20
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module DSL
|
|
5
|
+
module Logger
|
|
6
|
+
include Grape::DSL::Settings
|
|
7
|
+
|
|
8
|
+
attr_writer :logger
|
|
9
|
+
|
|
10
|
+
# Set or retrive the configured logger. If none was configured, this
|
|
11
|
+
# method will create a new one, logging to stdout.
|
|
12
|
+
# @param logger [Object] the new logger to use
|
|
13
|
+
def logger(logger = nil)
|
|
14
|
+
if logger
|
|
15
|
+
global_setting(:logger, logger)
|
|
16
|
+
else
|
|
17
|
+
global_setting(:logger) || global_setting(:logger, ::Logger.new($stdout))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module DSL
|
|
5
|
+
module Middleware
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
include Grape::DSL::Configuration
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
# Apply a custom middleware to the API. Applies
|
|
12
|
+
# to the current namespace and any children, but
|
|
13
|
+
# not parents.
|
|
14
|
+
#
|
|
15
|
+
# @param middleware_class [Class] The class of the middleware you'd like
|
|
16
|
+
# to inject.
|
|
17
|
+
def use(middleware_class, *args, &block)
|
|
18
|
+
arr = [:use, middleware_class, *args]
|
|
19
|
+
arr << block if block
|
|
20
|
+
|
|
21
|
+
namespace_stackable(:middleware, arr)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def insert(*args, &block)
|
|
25
|
+
arr = [:insert, *args]
|
|
26
|
+
arr << block if block
|
|
27
|
+
|
|
28
|
+
namespace_stackable(:middleware, arr)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def insert_before(*args, &block)
|
|
32
|
+
arr = [:insert_before, *args]
|
|
33
|
+
arr << block if block
|
|
34
|
+
|
|
35
|
+
namespace_stackable(:middleware, arr)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def insert_after(*args, &block)
|
|
39
|
+
arr = [:insert_after, *args]
|
|
40
|
+
arr << block if block
|
|
41
|
+
|
|
42
|
+
namespace_stackable(:middleware, arr)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Retrieve an array of the middleware classes
|
|
46
|
+
# and arguments that are currently applied to the
|
|
47
|
+
# application.
|
|
48
|
+
def middleware
|
|
49
|
+
namespace_stackable(:middleware) || []
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module DSL
|
|
5
|
+
# Defines DSL methods, meant to be applied to a ParamsScope, which define
|
|
6
|
+
# and describe the parameters accepted by an endpoint, or all endpoints
|
|
7
|
+
# within a namespace.
|
|
8
|
+
module Parameters
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
# Set the module used to build the request.params.
|
|
12
|
+
#
|
|
13
|
+
# @param build_with the ParamBuilder module to use when building request.params
|
|
14
|
+
# Available builders are:
|
|
15
|
+
#
|
|
16
|
+
# * Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder (default)
|
|
17
|
+
# * Grape::Extensions::Hash::ParamBuilder
|
|
18
|
+
# * Grape::Extensions::Hashie::Mash::ParamBuilder
|
|
19
|
+
#
|
|
20
|
+
# @example
|
|
21
|
+
#
|
|
22
|
+
# require 'grape/extenstions/hashie_mash'
|
|
23
|
+
# class API < Grape::API
|
|
24
|
+
# desc "Get collection"
|
|
25
|
+
# params do
|
|
26
|
+
# build_with :hashie_mash
|
|
27
|
+
# requires :user_id, type: Integer
|
|
28
|
+
# end
|
|
29
|
+
# get do
|
|
30
|
+
# params['user_id']
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
def build_with(build_with)
|
|
34
|
+
@api.namespace_inheritable(:build_params_with, build_with)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Include reusable params rules among current.
|
|
38
|
+
# You can define reusable params with helpers method.
|
|
39
|
+
#
|
|
40
|
+
# @example
|
|
41
|
+
#
|
|
42
|
+
# class API < Grape::API
|
|
43
|
+
# helpers do
|
|
44
|
+
# params :pagination do
|
|
45
|
+
# optional :page, type: Integer
|
|
46
|
+
# optional :per_page, type: Integer
|
|
47
|
+
# end
|
|
48
|
+
# end
|
|
49
|
+
#
|
|
50
|
+
# desc "Get collection"
|
|
51
|
+
# params do
|
|
52
|
+
# use :pagination
|
|
53
|
+
# end
|
|
54
|
+
# get do
|
|
55
|
+
# Collection.page(params[:page]).per(params[:per_page])
|
|
56
|
+
# end
|
|
57
|
+
# end
|
|
58
|
+
def use(*names)
|
|
59
|
+
named_params = @api.namespace_stackable_with_hash(:named_params) || {}
|
|
60
|
+
options = names.extract_options!
|
|
61
|
+
names.each do |name|
|
|
62
|
+
params_block = named_params.fetch(name) do
|
|
63
|
+
raise "Params :#{name} not found!"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
if options.empty?
|
|
67
|
+
instance_exec(options, ¶ms_block)
|
|
68
|
+
else
|
|
69
|
+
instance_exec(**options, ¶ms_block)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
alias use_scope use
|
|
74
|
+
alias includes use
|
|
75
|
+
|
|
76
|
+
# Require one or more parameters for the current endpoint.
|
|
77
|
+
#
|
|
78
|
+
# @param attrs list of parameters names, or, if :using is
|
|
79
|
+
# passed as an option, which keys to include (:all or :none) from
|
|
80
|
+
# the :using hash. The last key can be a hash, which specifies
|
|
81
|
+
# options for the parameters
|
|
82
|
+
# @option attrs :type [Class] the type to coerce this parameter to before
|
|
83
|
+
# passing it to the endpoint. See {Grape::Validations::Types} for a list of
|
|
84
|
+
# types that are supported automatically. Custom classes may be used
|
|
85
|
+
# where they define a class-level `::parse` method, or in conjunction
|
|
86
|
+
# with the `:coerce_with` parameter. `JSON` may be supplied to denote
|
|
87
|
+
# `JSON`-formatted objects or arrays of objects. `Array[JSON]` accepts
|
|
88
|
+
# the same values as `JSON` but will wrap single objects in an `Array`.
|
|
89
|
+
# @option attrs :types [Array<Class>] may be supplied in place of +:type+
|
|
90
|
+
# to declare an attribute that has multiple allowed types. See
|
|
91
|
+
# {Validations::Types::MultipleTypeCoercer} for more details on coercion
|
|
92
|
+
# and validation rules for variant-type parameters.
|
|
93
|
+
# @option attrs :desc [String] description to document this parameter
|
|
94
|
+
# @option attrs :default [Object] default value, if parameter is optional
|
|
95
|
+
# @option attrs :values [Array] permissable values for this field. If any
|
|
96
|
+
# other value is given, it will be handled as a validation error
|
|
97
|
+
# @option attrs :using [Hash[Symbol => Hash]] a hash defining keys and
|
|
98
|
+
# options, like that returned by {Grape::Entity#documentation}. The value
|
|
99
|
+
# of each key is an options hash accepting the same parameters
|
|
100
|
+
# @option attrs :except [Array[Symbol]] a list of keys to exclude from
|
|
101
|
+
# the :using Hash. The meaning of this depends on if :all or :none was
|
|
102
|
+
# passed; :all + :except will make the :except fields optional, whereas
|
|
103
|
+
# :none + :except will make the :except fields required
|
|
104
|
+
# @option attrs :coerce_with [#parse, #call] method to be used when coercing
|
|
105
|
+
# the parameter to the type named by `attrs[:type]`. Any class or object
|
|
106
|
+
# that defines `::parse` or `::call` may be used.
|
|
107
|
+
#
|
|
108
|
+
# @example
|
|
109
|
+
#
|
|
110
|
+
# params do
|
|
111
|
+
# # Basic usage: require a parameter of a certain type
|
|
112
|
+
# requires :user_id, type: Integer
|
|
113
|
+
#
|
|
114
|
+
# # You don't need to specify type; String is default
|
|
115
|
+
# requires :foo
|
|
116
|
+
#
|
|
117
|
+
# # Multiple params can be specified at once if they share
|
|
118
|
+
# # the same options.
|
|
119
|
+
# requires :x, :y, :z, type: Date
|
|
120
|
+
#
|
|
121
|
+
# # Nested parameters can be handled as hashes. You must
|
|
122
|
+
# # pass in a block, within which you can use any of the
|
|
123
|
+
# # parameters DSL methods.
|
|
124
|
+
# requires :user, type: Hash do
|
|
125
|
+
# requires :name, type: String
|
|
126
|
+
# end
|
|
127
|
+
# end
|
|
128
|
+
def requires(*attrs, &block)
|
|
129
|
+
orig_attrs = attrs.clone
|
|
130
|
+
|
|
131
|
+
opts = attrs.extract_options!.clone
|
|
132
|
+
opts[:presence] = { value: true, message: opts[:message] }
|
|
133
|
+
opts = @group.deep_merge(opts) if instance_variable_defined?(:@group) && @group
|
|
134
|
+
|
|
135
|
+
if opts[:using]
|
|
136
|
+
require_required_and_optional_fields(attrs.first, opts)
|
|
137
|
+
else
|
|
138
|
+
validate_attributes(attrs, opts, &block)
|
|
139
|
+
block ? new_scope(orig_attrs, &block) : push_declared_params(attrs, opts.slice(:as))
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Allow, but don't require, one or more parameters for the current
|
|
144
|
+
# endpoint.
|
|
145
|
+
# @param (see #requires)
|
|
146
|
+
# @option (see #requires)
|
|
147
|
+
def optional(*attrs, &block)
|
|
148
|
+
orig_attrs = attrs.clone
|
|
149
|
+
|
|
150
|
+
opts = attrs.extract_options!.clone
|
|
151
|
+
type = opts[:type]
|
|
152
|
+
opts = @group.deep_merge(opts) if instance_variable_defined?(:@group) && @group
|
|
153
|
+
|
|
154
|
+
# check type for optional parameter group
|
|
155
|
+
if attrs && block
|
|
156
|
+
raise Grape::Exceptions::MissingGroupType if type.nil?
|
|
157
|
+
raise Grape::Exceptions::UnsupportedGroupType unless Grape::Validations::Types.group?(type)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
if opts[:using]
|
|
161
|
+
require_optional_fields(attrs.first, opts)
|
|
162
|
+
else
|
|
163
|
+
validate_attributes(attrs, opts, &block)
|
|
164
|
+
|
|
165
|
+
block ? new_scope(orig_attrs, true, &block) : push_declared_params(attrs, opts.slice(:as))
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Define common settings for one or more parameters
|
|
170
|
+
# @param (see #requires)
|
|
171
|
+
# @option (see #requires)
|
|
172
|
+
def with(*attrs, &block)
|
|
173
|
+
new_group_attrs = [@group, attrs.clone.first].compact.reduce(&:deep_merge)
|
|
174
|
+
new_group_scope([new_group_attrs], &block)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Disallow the given parameters to be present in the same request.
|
|
178
|
+
# @param attrs [*Symbol] parameters to validate
|
|
179
|
+
def mutually_exclusive(*attrs)
|
|
180
|
+
validates(attrs, mutual_exclusion: { value: true, message: extract_message_option(attrs) })
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Require exactly one of the given parameters to be present.
|
|
184
|
+
# @param (see #mutually_exclusive)
|
|
185
|
+
def exactly_one_of(*attrs)
|
|
186
|
+
validates(attrs, exactly_one_of: { value: true, message: extract_message_option(attrs) })
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Require at least one of the given parameters to be present.
|
|
190
|
+
# @param (see #mutually_exclusive)
|
|
191
|
+
def at_least_one_of(*attrs)
|
|
192
|
+
validates(attrs, at_least_one_of: { value: true, message: extract_message_option(attrs) })
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Require that either all given params are present, or none are.
|
|
196
|
+
# @param (see #mutually_exclusive)
|
|
197
|
+
def all_or_none_of(*attrs)
|
|
198
|
+
validates(attrs, all_or_none_of: { value: true, message: extract_message_option(attrs) })
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Define a block of validations which should be applied if and only if
|
|
202
|
+
# the given parameter is present. The parameters are not nested.
|
|
203
|
+
# @param attr [Symbol] the parameter which, if present, triggers the
|
|
204
|
+
# validations
|
|
205
|
+
# @raise Grape::Exceptions::UnknownParameter if `attr` has not been
|
|
206
|
+
# defined in this scope yet
|
|
207
|
+
# @yield a parameter definition DSL
|
|
208
|
+
def given(*attrs, &block)
|
|
209
|
+
attrs.each do |attr|
|
|
210
|
+
proxy_attr = first_hash_key_or_param(attr)
|
|
211
|
+
raise Grape::Exceptions::UnknownParameter.new(proxy_attr) unless declared_param?(proxy_attr)
|
|
212
|
+
end
|
|
213
|
+
new_lateral_scope(dependent_on: attrs, &block)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Test for whether a certain parameter has been defined in this params
|
|
217
|
+
# block yet.
|
|
218
|
+
# @return [Boolean] whether the parameter has been defined
|
|
219
|
+
def declared_param?(param)
|
|
220
|
+
if lateral?
|
|
221
|
+
# Elements of @declared_params of lateral scope are pushed in @parent. So check them in @parent.
|
|
222
|
+
@parent.declared_param?(param)
|
|
223
|
+
else
|
|
224
|
+
# @declared_params also includes hashes of options and such, but those
|
|
225
|
+
# won't be flattened out.
|
|
226
|
+
@declared_params.flatten.any? do |declared_param_attr|
|
|
227
|
+
first_hash_key_or_param(declared_param_attr.key) == param
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
alias group requires
|
|
233
|
+
|
|
234
|
+
class EmptyOptionalValue; end # rubocop:disable Lint/EmptyClass
|
|
235
|
+
|
|
236
|
+
def map_params(params, element, is_array = false)
|
|
237
|
+
if params.is_a?(Array)
|
|
238
|
+
params.map do |el|
|
|
239
|
+
map_params(el, element, true)
|
|
240
|
+
end
|
|
241
|
+
elsif params.is_a?(Hash)
|
|
242
|
+
params[element] || (@optional && is_array ? EmptyOptionalValue : {})
|
|
243
|
+
elsif params == EmptyOptionalValue
|
|
244
|
+
EmptyOptionalValue
|
|
245
|
+
else
|
|
246
|
+
{}
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# @param params [Hash] initial hash of parameters
|
|
251
|
+
# @return hash of parameters relevant for the current scope
|
|
252
|
+
# @api private
|
|
253
|
+
def params(params)
|
|
254
|
+
params = @parent.params_meeting_dependency.presence || @parent.params(params) if instance_variable_defined?(:@parent) && @parent
|
|
255
|
+
params = map_params(params, @element) if instance_variable_defined?(:@element) && @element
|
|
256
|
+
params
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
private
|
|
260
|
+
|
|
261
|
+
def first_hash_key_or_param(parameter)
|
|
262
|
+
parameter.is_a?(Hash) ? parameter.keys.first : parameter
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
end
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module DSL
|
|
5
|
+
module RequestResponse
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
include Grape::DSL::Configuration
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
# Specify the default format for the API's serializers.
|
|
12
|
+
# May be `:json` or `:txt` (default).
|
|
13
|
+
def default_format(new_format = nil)
|
|
14
|
+
namespace_inheritable(:default_format, new_format.nil? ? nil : new_format.to_sym)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Specify the format for the API's serializers.
|
|
18
|
+
# May be `:json`, `:xml`, `:txt`, etc.
|
|
19
|
+
def format(new_format = nil)
|
|
20
|
+
return namespace_inheritable(:format) unless new_format
|
|
21
|
+
|
|
22
|
+
symbolic_new_format = new_format.to_sym
|
|
23
|
+
namespace_inheritable(:format, symbolic_new_format)
|
|
24
|
+
namespace_inheritable(:default_error_formatter, Grape::ErrorFormatter.formatter_for(symbolic_new_format))
|
|
25
|
+
|
|
26
|
+
content_type = content_types[symbolic_new_format]
|
|
27
|
+
raise Grape::Exceptions::MissingMimeType.new(new_format) unless content_type
|
|
28
|
+
|
|
29
|
+
namespace_stackable(:content_types, symbolic_new_format => content_type)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Specify a custom formatter for a content-type.
|
|
33
|
+
def formatter(content_type, new_formatter)
|
|
34
|
+
namespace_stackable(:formatters, content_type.to_sym => new_formatter)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Specify a custom parser for a content-type.
|
|
38
|
+
def parser(content_type, new_parser)
|
|
39
|
+
namespace_stackable(:parsers, content_type.to_sym => new_parser)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Specify a default error formatter.
|
|
43
|
+
def default_error_formatter(new_formatter_name = nil)
|
|
44
|
+
return namespace_inheritable(:default_error_formatter) unless new_formatter_name
|
|
45
|
+
|
|
46
|
+
new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name)
|
|
47
|
+
namespace_inheritable(:default_error_formatter, new_formatter)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def error_formatter(format, options)
|
|
51
|
+
formatter = if options.is_a?(Hash) && options.key?(:with)
|
|
52
|
+
options[:with]
|
|
53
|
+
else
|
|
54
|
+
options
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
namespace_stackable(:error_formatters, format.to_sym => formatter)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Specify additional content-types, e.g.:
|
|
61
|
+
# content_type :xls, 'application/vnd.ms-excel'
|
|
62
|
+
def content_type(key, val)
|
|
63
|
+
namespace_stackable(:content_types, key.to_sym => val)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# All available content types.
|
|
67
|
+
def content_types
|
|
68
|
+
c_types = namespace_stackable_with_hash(:content_types)
|
|
69
|
+
Grape::ContentTypes.content_types_for c_types
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Specify the default status code for errors.
|
|
73
|
+
def default_error_status(new_status = nil)
|
|
74
|
+
namespace_inheritable(:default_error_status, new_status)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Allows you to rescue certain exceptions that occur to return
|
|
78
|
+
# a grape error rather than raising all the way to the
|
|
79
|
+
# server level.
|
|
80
|
+
#
|
|
81
|
+
# @example Rescue from custom exceptions
|
|
82
|
+
# class ExampleAPI < Grape::API
|
|
83
|
+
# class CustomError < StandardError; end
|
|
84
|
+
#
|
|
85
|
+
# rescue_from CustomError
|
|
86
|
+
# end
|
|
87
|
+
#
|
|
88
|
+
# @overload rescue_from(*exception_classes, **options)
|
|
89
|
+
# @param [Array] exception_classes A list of classes that you want to rescue, or
|
|
90
|
+
# the symbol :all to rescue from all exceptions.
|
|
91
|
+
# @param [Block] block Execution block to handle the given exception.
|
|
92
|
+
# @param [Hash] options Options for the rescue usage.
|
|
93
|
+
# @option options [Boolean] :backtrace Include a backtrace in the rescue response.
|
|
94
|
+
# @option options [Boolean] :rescue_subclasses Also rescue subclasses of exception classes
|
|
95
|
+
# @param [Proc] handler Execution proc to handle the given exception as an
|
|
96
|
+
# alternative to passing a block.
|
|
97
|
+
def rescue_from(*args, &block)
|
|
98
|
+
if args.last.is_a?(Proc)
|
|
99
|
+
handler = args.pop
|
|
100
|
+
elsif block
|
|
101
|
+
handler = block
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
options = args.extract_options!
|
|
105
|
+
raise ArgumentError, 'both :with option and block cannot be passed' if block && options.key?(:with)
|
|
106
|
+
|
|
107
|
+
handler ||= extract_with(options)
|
|
108
|
+
|
|
109
|
+
if args.include?(:all)
|
|
110
|
+
namespace_inheritable(:rescue_all, true)
|
|
111
|
+
namespace_inheritable(:all_rescue_handler, handler)
|
|
112
|
+
elsif args.include?(:grape_exceptions)
|
|
113
|
+
namespace_inheritable(:rescue_all, true)
|
|
114
|
+
namespace_inheritable(:rescue_grape_exceptions, true)
|
|
115
|
+
namespace_inheritable(:grape_exceptions_rescue_handler, handler)
|
|
116
|
+
else
|
|
117
|
+
handler_type =
|
|
118
|
+
case options[:rescue_subclasses]
|
|
119
|
+
when nil, true
|
|
120
|
+
:rescue_handlers
|
|
121
|
+
else
|
|
122
|
+
:base_only_rescue_handlers
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
namespace_reverse_stackable(handler_type, args.to_h { |arg| [arg, handler] })
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
namespace_stackable(:rescue_options, options)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Allows you to specify a default representation entity for a
|
|
132
|
+
# class. This allows you to map your models to their respective
|
|
133
|
+
# entities once and then simply call `present` with the model.
|
|
134
|
+
#
|
|
135
|
+
# @example
|
|
136
|
+
# class ExampleAPI < Grape::API
|
|
137
|
+
# represent User, with: Entity::User
|
|
138
|
+
#
|
|
139
|
+
# get '/me' do
|
|
140
|
+
# present current_user # with: Entity::User is assumed
|
|
141
|
+
# end
|
|
142
|
+
# end
|
|
143
|
+
#
|
|
144
|
+
# Note that Grape will automatically go up the class ancestry to
|
|
145
|
+
# try to find a representing entity, so if you, for example, define
|
|
146
|
+
# an entity to represent `Object` then all presented objects will
|
|
147
|
+
# bubble up and utilize the entity provided on that `represent` call.
|
|
148
|
+
#
|
|
149
|
+
# @param model_class [Class] The model class that will be represented.
|
|
150
|
+
# @option options [Class] :with The entity class that will represent the model.
|
|
151
|
+
def represent(model_class, options)
|
|
152
|
+
raise Grape::Exceptions::InvalidWithOptionForRepresent.new unless options[:with].is_a?(Class)
|
|
153
|
+
|
|
154
|
+
namespace_stackable(:representations, model_class => options[:with])
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
private
|
|
158
|
+
|
|
159
|
+
def extract_with(options)
|
|
160
|
+
return unless options.key?(:with)
|
|
161
|
+
|
|
162
|
+
with_option = options.delete(:with)
|
|
163
|
+
return with_option if with_option.instance_of?(Proc)
|
|
164
|
+
return with_option.to_sym if with_option.instance_of?(Symbol) || with_option.instance_of?(String)
|
|
165
|
+
|
|
166
|
+
raise ArgumentError, "with: #{with_option.class}, expected Symbol, String or Proc"
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|