grape 1.6.2 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/README.md +120 -19
  4. data/UPGRADING.md +15 -0
  5. data/lib/grape/api/instance.rb +1 -1
  6. data/lib/grape/dry_types.rb +12 -0
  7. data/lib/grape/dsl/api.rb +0 -2
  8. data/lib/grape/dsl/callbacks.rb +0 -2
  9. data/lib/grape/dsl/configuration.rb +0 -2
  10. data/lib/grape/dsl/desc.rb +0 -15
  11. data/lib/grape/dsl/helpers.rb +0 -2
  12. data/lib/grape/dsl/inside_route.rb +33 -29
  13. data/lib/grape/dsl/middleware.rb +0 -2
  14. data/lib/grape/dsl/parameters.rb +5 -7
  15. data/lib/grape/dsl/request_response.rb +0 -2
  16. data/lib/grape/dsl/routing.rb +4 -2
  17. data/lib/grape/dsl/settings.rb +0 -2
  18. data/lib/grape/dsl/validations.rb +0 -15
  19. data/lib/grape/error_formatter/json.rb +7 -1
  20. data/lib/grape/exceptions/base.rb +2 -2
  21. data/lib/grape/exceptions/missing_group_type.rb +8 -1
  22. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  23. data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
  24. data/lib/grape/exceptions/validation.rb +0 -4
  25. data/lib/grape/locale/en.yml +9 -8
  26. data/lib/grape/middleware/auth/dsl.rb +0 -1
  27. data/lib/grape/middleware/error.rb +2 -2
  28. data/lib/grape/request.rb +2 -0
  29. data/lib/grape/util/json.rb +2 -0
  30. data/lib/grape/validations/attributes_doc.rb +58 -0
  31. data/lib/grape/validations/params_scope.rb +66 -40
  32. data/lib/grape/validations/types/array_coercer.rb +0 -2
  33. data/lib/grape/validations/types/dry_type_coercer.rb +3 -7
  34. data/lib/grape/validations/types/primitive_coercer.rb +14 -6
  35. data/lib/grape/validations/types/set_coercer.rb +0 -2
  36. data/lib/grape/validations/types.rb +98 -30
  37. data/lib/grape/validations/validators/{all_or_none.rb → all_or_none_of_validator.rb} +0 -2
  38. data/lib/grape/validations/validators/{allow_blank.rb → allow_blank_validator.rb} +0 -0
  39. data/lib/grape/validations/validators/{as.rb → as_validator.rb} +0 -0
  40. data/lib/grape/validations/validators/{at_least_one_of.rb → at_least_one_of_validator.rb} +0 -2
  41. data/lib/grape/validations/validators/base.rb +7 -0
  42. data/lib/grape/validations/validators/{coerce.rb → coerce_validator.rb} +0 -0
  43. data/lib/grape/validations/validators/{default.rb → default_validator.rb} +0 -0
  44. data/lib/grape/validations/validators/{exactly_one_of.rb → exactly_one_of_validator.rb} +0 -2
  45. data/lib/grape/validations/validators/{except_values.rb → except_values_validator.rb} +0 -0
  46. data/lib/grape/validations/validators/{mutual_exclusion.rb → mutual_exclusion_validator.rb} +0 -2
  47. data/lib/grape/validations/validators/{presence.rb → presence_validator.rb} +0 -0
  48. data/lib/grape/validations/validators/{regexp.rb → regexp_validator.rb} +0 -0
  49. data/lib/grape/validations/validators/{same_as.rb → same_as_validator.rb} +0 -0
  50. data/lib/grape/validations/validators/{values.rb → values_validator.rb} +0 -0
  51. data/lib/grape/validations.rb +16 -12
  52. data/lib/grape/version.rb +1 -1
  53. data/lib/grape.rb +66 -28
  54. data/spec/grape/api/custom_validations_spec.rb +41 -2
  55. data/spec/grape/api/deeply_included_options_spec.rb +0 -2
  56. data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -2
  57. data/spec/grape/api/documentation_spec.rb +59 -0
  58. data/spec/grape/api/inherited_helpers_spec.rb +0 -2
  59. data/spec/grape/api/instance_spec.rb +0 -1
  60. data/spec/grape/api/invalid_format_spec.rb +0 -2
  61. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
  62. data/spec/grape/api/nested_helpers_spec.rb +0 -2
  63. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
  64. data/spec/grape/api/parameters_modification_spec.rb +0 -2
  65. data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
  66. data/spec/grape/api/recognize_path_spec.rb +0 -2
  67. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
  68. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
  69. data/spec/grape/api/routes_with_requirements_spec.rb +0 -2
  70. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -2
  71. data/spec/grape/api/shared_helpers_spec.rb +0 -2
  72. data/spec/grape/api_remount_spec.rb +0 -1
  73. data/spec/grape/api_spec.rb +18 -5
  74. data/spec/grape/config_spec.rb +0 -2
  75. data/spec/grape/dsl/callbacks_spec.rb +0 -2
  76. data/spec/grape/dsl/configuration_spec.rb +0 -2
  77. data/spec/grape/dsl/desc_spec.rb +0 -2
  78. data/spec/grape/dsl/headers_spec.rb +2 -4
  79. data/spec/grape/dsl/helpers_spec.rb +0 -2
  80. data/spec/grape/dsl/inside_route_spec.rb +10 -12
  81. data/spec/grape/dsl/logger_spec.rb +0 -2
  82. data/spec/grape/dsl/middleware_spec.rb +0 -2
  83. data/spec/grape/dsl/parameters_spec.rb +0 -2
  84. data/spec/grape/dsl/request_response_spec.rb +6 -8
  85. data/spec/grape/dsl/routing_spec.rb +1 -3
  86. data/spec/grape/dsl/settings_spec.rb +0 -2
  87. data/spec/grape/dsl/validations_spec.rb +0 -17
  88. data/spec/grape/endpoint/declared_spec.rb +2 -4
  89. data/spec/grape/endpoint_spec.rb +22 -3
  90. data/spec/grape/entity_spec.rb +0 -1
  91. data/spec/grape/exceptions/base_spec.rb +16 -2
  92. data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -2
  93. data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -2
  94. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
  95. data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
  96. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
  97. data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
  98. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
  99. data/spec/grape/exceptions/missing_option_spec.rb +1 -3
  100. data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
  101. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
  102. data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
  103. data/spec/grape/exceptions/validation_errors_spec.rb +0 -1
  104. data/spec/grape/exceptions/validation_spec.rb +1 -3
  105. data/spec/grape/extensions/param_builders/hash_spec.rb +0 -2
  106. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -2
  107. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -2
  108. data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
  109. data/spec/grape/integration/rack_sendfile_spec.rb +0 -2
  110. data/spec/grape/integration/rack_spec.rb +0 -2
  111. data/spec/grape/loading_spec.rb +0 -2
  112. data/spec/grape/middleware/auth/base_spec.rb +0 -1
  113. data/spec/grape/middleware/auth/dsl_spec.rb +0 -2
  114. data/spec/grape/middleware/auth/strategies_spec.rb +0 -2
  115. data/spec/grape/middleware/base_spec.rb +0 -2
  116. data/spec/grape/middleware/error_spec.rb +6 -1
  117. data/spec/grape/middleware/exception_spec.rb +0 -2
  118. data/spec/grape/middleware/formatter_spec.rb +0 -2
  119. data/spec/grape/middleware/globals_spec.rb +0 -2
  120. data/spec/grape/middleware/stack_spec.rb +0 -2
  121. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -2
  122. data/spec/grape/middleware/versioner/header_spec.rb +18 -4
  123. data/spec/grape/middleware/versioner/param_spec.rb +0 -2
  124. data/spec/grape/middleware/versioner/path_spec.rb +0 -2
  125. data/spec/grape/middleware/versioner_spec.rb +0 -2
  126. data/spec/grape/named_api_spec.rb +0 -2
  127. data/spec/grape/parser_spec.rb +0 -2
  128. data/spec/grape/path_spec.rb +0 -2
  129. data/spec/grape/presenters/presenter_spec.rb +0 -2
  130. data/spec/grape/request_spec.rb +0 -2
  131. data/spec/grape/util/inheritable_setting_spec.rb +0 -1
  132. data/spec/grape/util/inheritable_values_spec.rb +0 -1
  133. data/spec/grape/util/reverse_stackable_values_spec.rb +0 -1
  134. data/spec/grape/util/stackable_values_spec.rb +0 -1
  135. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
  136. data/spec/grape/validations/attributes_doc_spec.rb +153 -0
  137. data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
  138. data/spec/grape/validations/instance_behaivour_spec.rb +0 -2
  139. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -2
  140. data/spec/grape/validations/params_scope_spec.rb +315 -86
  141. data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -2
  142. data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
  143. data/spec/grape/validations/types/primitive_coercer_spec.rb +20 -5
  144. data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
  145. data/spec/grape/validations/types_spec.rb +28 -2
  146. data/spec/grape/validations/validators/all_or_none_spec.rb +0 -2
  147. data/spec/grape/validations/validators/allow_blank_spec.rb +0 -2
  148. data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -2
  149. data/spec/grape/validations/validators/coerce_spec.rb +0 -2
  150. data/spec/grape/validations/validators/default_spec.rb +0 -2
  151. data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -2
  152. data/spec/grape/validations/validators/except_values_spec.rb +0 -2
  153. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -2
  154. data/spec/grape/validations/validators/presence_spec.rb +0 -2
  155. data/spec/grape/validations/validators/regexp_spec.rb +0 -2
  156. data/spec/grape/validations/validators/same_as_spec.rb +0 -2
  157. data/spec/grape/validations/validators/values_spec.rb +0 -2
  158. data/spec/grape/validations_spec.rb +50 -22
  159. data/spec/integration/multi_json/json_spec.rb +0 -2
  160. data/spec/integration/multi_xml/xml_spec.rb +0 -2
  161. data/spec/spec_helper.rb +9 -4
  162. metadata +30 -21
  163. data/spec/support/eager_load.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d182a6dfa2a571345d24a6a2b7286b4a2b34eeedc6570334ba2259fdda59faac
4
- data.tar.gz: c365091e871e7ad78dd46dc0aab52cdd41d1e5ddb5a46503fcf0020af45f4324
3
+ metadata.gz: c13bf4d5de206b76e7cccbe4ffa454512986457b8f5d055cde0cfac5d4f164a9
4
+ data.tar.gz: 1177df9af2a24d80e01366f3d705f29e4180898f4cc1ac7e0221e8412e36dcf1
5
5
  SHA512:
6
- metadata.gz: 539fdf761a5058dfcb3bab993a7fac3c7223ec06e0b828e102cb52095ac79f63668ebab1c1c4b47bf16984990c94f9a291537e7b2a1359626736b7abdd2c34ec
7
- data.tar.gz: 2b30d941ab114aab53c4f4630742adedd037856ecc63b65f87b0df506349a13eed092964d9f53c003774006e74b9800043178b2ad2e6c55b0d5d42f6039a7e71
6
+ metadata.gz: 32a0d1d9ae7d16b9760f8919814b2aa362ec95a666159a6dc8314946e8a9fd2461d8c074f705ac7afa21939d2a43bec4196a8b7803efdae967b2d01acd1ae77a
7
+ data.tar.gz: 5ca9d54a6db6bc63107c2bd0b17cb747f293ec72bc3c0d57a7f7514f0c1122774bce82c5411f4fa19f1c7b435d2c3d1d87102e3f83ff5c31aa8a0dc531817e4d
data/CHANGELOG.md CHANGED
@@ -1,7 +1,35 @@
1
- ### 1.6.2 (2021/12/30)
1
+ ### 1.7.0 (2022/12/20)
2
2
 
3
3
  #### Features
4
4
 
5
+ * [#2233](https://github.com/ruby-grape/grape/pull/2233): Added `do_not_document!` for disabling documentation to internal APIs - [@dnesteryuk](https://github.com/dnesteryuk).
6
+ * [#2235](https://github.com/ruby-grape/grape/pull/2235): Add support for Ruby 3.1 - [@petergoldstein](https://github.com/petergoldstein).
7
+ * [#2248](https://github.com/ruby-grape/grape/pull/2248): Upgraded to rspec 3.11.0 - [@dblock](https://github.com/dblock).
8
+ * [#2249](https://github.com/ruby-grape/grape/pull/2249): Split CI matrix, extract edge - [@dblock](https://github.com/dblock).
9
+ * [#2249](https://github.com/ruby-grape/grape/pull/2251): Upgraded to RuboCop 1.25.1 - [@dblock](https://github.com/dblock).
10
+ * [#2271](https://github.com/ruby-grape/grape/pull/2271): Fixed validation regression on Numeric type introduced in 1.3 - [@vasfed](https://github.com/Vasfed).
11
+ * [#2267](https://github.com/ruby-grape/grape/pull/2267): Standardized English error messages - [@dblock](https://github.com/dblock).
12
+ * [#2272](https://github.com/ruby-grape/grape/pull/2272): Added error on param init when provided type does not have `[]` coercion method, previously validation silently failed for any value - [@vasfed](https://github.com/Vasfed).
13
+ * [#2274](https://github.com/ruby-grape/grape/pull/2274): Error middleware support using rack util's symbols as status - [@dhruvCW](https://github.com/dhruvCW).
14
+ * [#2276](https://github.com/ruby-grape/grape/pull/2276): Fix exception super - [@ericproulx](https://github.com/ericproulx).
15
+ * [#2285](https://github.com/ruby-grape/grape/pull/2285), [#2287](https://github.com/ruby-grape/grape/pull/2287): Added :evaluate_given to declared(params) - [@zysend](https://github.com/zysend).
16
+
17
+ #### Fixes
18
+
19
+ * [#2263](https://github.com/ruby-grape/grape/pull/2263): Explicitly require `bigdecimal` and `date` - [@dblock](https://github.com/dblock).
20
+ * [#2222](https://github.com/ruby-grape/grape/pull/2222): Autoload types and validators - [@ericproulx](https://github.com/ericproulx).
21
+ * [#2232](https://github.com/ruby-grape/grape/pull/2232): Fix kwargs support in shared params definition - [@dm1try](https://github.com/dm1try).
22
+ * [#2229](https://github.com/ruby-grape/grape/pull/2229): Do not collect params in route settings - [@dnesteryuk](https://github.com/dnesteryuk).
23
+ * [#2234](https://github.com/ruby-grape/grape/pull/2234): Remove non-UTF8 characters from format before generating JSON error - [@bschmeck](https://github.com/bschmeck).
24
+ * [#2227](https://github.com/ruby-grape/grape/pull/2222): Rename `MissingGroupType` and `UnsupportedGroupType` exceptions - [@ericproulx](https://github.com/ericproulx).
25
+ * [#2244](https://github.com/ruby-grape/grape/pull/2244): Fix a breaking change in `Grape::Validations` provided in 1.6.1 - [@dm1try](https://github.com/dm1try).
26
+ * [#2250](https://github.com/ruby-grape/grape/pull/2250): Add deprecation warning for `UnsupportedGroupTypeError` and `MissingGroupTypeError` - [@ericproulx](https://github.com/ericproulx).
27
+ * [#2256](https://github.com/ruby-grape/grape/pull/2256): Raise `Grape::Exceptions::MultipartPartLimitError` from Rack when too many files are uploaded - [@bschmeck](https://github.com/bschmeck).
28
+ * [#2266](https://github.com/ruby-grape/grape/pull/2266): Fix code coverage - [@duffn](https://github.com/duffn).
29
+ * [#2284](https://github.com/ruby-grape/grape/pull/2284): Fix an unexpected backtick - [@zysend](https://github.com/zysend).
30
+
31
+ ### 1.6.2 (2021/12/30)
32
+
5
33
  #### Fixes
6
34
 
7
35
  * [#2219](https://github.com/ruby-grape/grape/pull/2219): Revert the changes for autoloading provided in 1.6.1 - [@dm1try](https://github.com/dm1try).
data/README.md CHANGED
@@ -40,6 +40,7 @@
40
40
  - [Declared](#declared)
41
41
  - [Include Parent Namespaces](#include-parent-namespaces)
42
42
  - [Include Missing](#include-missing)
43
+ - [Evaluate Given](#evaluate-given)
43
44
  - [Parameter Validation and Coercion](#parameter-validation-and-coercion)
44
45
  - [Supported Parameter Types](#supported-parameter-types)
45
46
  - [Integer/Fixnum and Coercions](#integerfixnum-and-coercions)
@@ -158,7 +159,7 @@ content negotiation, versioning and much more.
158
159
 
159
160
  ## Stable Release
160
161
 
161
- You're reading the documentation for the stable release of Grape, **1.6.2**.
162
+ You're reading the documentation for the stable release of Grape, 1.7.0.
162
163
  Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
163
164
 
164
165
  ## Project Resources
@@ -174,21 +175,13 @@ Available as part of the Tidelift Subscription.
174
175
 
175
176
  The maintainers of Grape are working with Tidelift to deliver commercial support and maintenance. Save time, reduce risk, and improve code health, while paying the maintainers of Grape. Click [here](https://tidelift.com/subscription/request-a-demo?utm_source=rubygems-grape&utm_medium=referral&utm_campaign=enterprise) for more details.
176
177
 
177
- In 2020, we plan to use the money towards gathering Grape contributors for dinner in New York City.
178
-
179
178
  ## Installation
180
179
 
181
180
  Ruby 2.4 or newer is required.
182
181
 
183
- Grape is available as a gem, to install it just install the gem:
184
-
185
- gem install grape
186
-
187
- If you're using Bundler, add the gem to Gemfile.
182
+ Grape is available as a gem, to install it run:
188
183
 
189
- gem 'grape'
190
-
191
- Run `bundle install`.
184
+ bundle add grape
192
185
 
193
186
  ## Basic Usage
194
187
 
@@ -1085,6 +1078,102 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d
1085
1078
  }
1086
1079
  ````
1087
1080
 
1081
+ ### Evaluate Given
1082
+
1083
+ By default `declared(params)` will not evaluate `given` and return all parameters. Use `evaluate_given` to evaluate all `given` blocks and return only parameters that satisfy `given` conditions. Consider the following API:
1084
+
1085
+ ````ruby
1086
+ format :json
1087
+
1088
+ params do
1089
+ optional :child_id, type: Integer
1090
+ given :child_id do
1091
+ requires :father_id, type: Integer
1092
+ end
1093
+ end
1094
+
1095
+ post 'child' do
1096
+ { 'declared_params' => declared(params, evaluate_given: true) }
1097
+ end
1098
+ ````
1099
+
1100
+ **Request**
1101
+
1102
+ ````bash
1103
+ curl -X POST -H "Content-Type: application/json" localhost:9292/child -d '{"father_id": 1}'
1104
+ ````
1105
+
1106
+ **Response with evaluate_given:false**
1107
+
1108
+ ````json
1109
+ {
1110
+ "declared_params": {
1111
+ "child_id": null,
1112
+ "father_id": 1
1113
+ }
1114
+ }
1115
+ ````
1116
+
1117
+ **Response with evaluate_given:true**
1118
+
1119
+ ````json
1120
+ {
1121
+ "declared_params": {
1122
+ "child_id": null
1123
+ }
1124
+ }
1125
+ ````
1126
+
1127
+ It also works on nested hashes:
1128
+
1129
+ ````ruby
1130
+ format :json
1131
+
1132
+ params do
1133
+ requires :child, type: Hash do
1134
+ optional :child_id, type: Integer
1135
+ given :child_id do
1136
+ requires :father_id, type: Integer
1137
+ end
1138
+ end
1139
+ end
1140
+
1141
+ post 'child' do
1142
+ { 'declared_params' => declared(params, evaluate_given: true) }
1143
+ end
1144
+ ````
1145
+
1146
+ **Request**
1147
+
1148
+ ````bash
1149
+ curl -X POST -H "Content-Type: application/json" localhost:9292/child -d '{"child": {"father_id": 1}}'
1150
+ ````
1151
+
1152
+ **Response with evaluate_given:false**
1153
+
1154
+ ````json
1155
+ {
1156
+ "declared_params": {
1157
+ "child": {
1158
+ "child_id": null,
1159
+ "father_id": 1
1160
+ }
1161
+ }
1162
+ }
1163
+ ````
1164
+
1165
+ **Response with evaluate_given:true**
1166
+
1167
+ ````json
1168
+ {
1169
+ "declared_params": {
1170
+ "child": {
1171
+ "child_id": null
1172
+ }
1173
+ }
1174
+ }
1175
+ ````
1176
+
1088
1177
  ## Parameter Validation and Coercion
1089
1178
 
1090
1179
  You can define validations and coercion options for your parameters using a `params` block.
@@ -1453,7 +1542,7 @@ resource :users do
1453
1542
  end
1454
1543
  ```
1455
1544
 
1456
- The value passed to `as` will be the key when calling `params` or `declared(params)`.
1545
+ The value passed to `as` will be the key when calling `declared(params)`.
1457
1546
 
1458
1547
  ### Built-in Validators
1459
1548
 
@@ -1742,10 +1831,10 @@ end
1742
1831
  ### Custom Validators
1743
1832
 
1744
1833
  ```ruby
1745
- class AlphaNumeric < Grape::Validations::Base
1834
+ class AlphaNumeric < Grape::Validations::Validators::Base
1746
1835
  def validate_param!(attr_name, params)
1747
1836
  unless params[attr_name] =~ /\A[[:alnum:]]+\z/
1748
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: 'must consist of alpha-numeric characters'
1837
+ raise Grape::Exceptions::Validation.new params: [@scope.full_name(attr_name)], message: 'must consist of alpha-numeric characters'
1749
1838
  end
1750
1839
  end
1751
1840
  end
@@ -1760,10 +1849,10 @@ end
1760
1849
  You can also create custom classes that take parameters.
1761
1850
 
1762
1851
  ```ruby
1763
- class Length < Grape::Validations::Base
1852
+ class Length < Grape::Validations::Validators::Base
1764
1853
  def validate_param!(attr_name, params)
1765
1854
  unless params[attr_name].length <= @option
1766
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long"
1855
+ raise Grape::Exceptions::Validation.new params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long"
1767
1856
  end
1768
1857
  end
1769
1858
  end
@@ -1778,7 +1867,7 @@ end
1778
1867
  You can also create custom validation that use request to validate the attribute. For example if you want to have parameters that are available to only admins, you can do the following.
1779
1868
 
1780
1869
  ```ruby
1781
- class Admin < Grape::Validations::Base
1870
+ class Admin < Grape::Validations::Validators::Base
1782
1871
  def validate(request)
1783
1872
  # return if the param we are checking was not in request
1784
1873
  # @attrs is a list containing the attribute we are currently validating
@@ -1789,7 +1878,7 @@ class Admin < Grape::Validations::Base
1789
1878
  return unless @option
1790
1879
  # check if user is admin or not
1791
1880
  # as an example get a token from request and check if it's admin or not
1792
- fail Grape::Exceptions::Validation, params: @attrs, message: 'Can not set admin-only field.' unless request.headers['X-Access-Token'] == 'admin'
1881
+ raise Grape::Exceptions::Validation.new params: @attrs, message: 'Can not set admin-only field.' unless request.headers['X-Access-Token'] == 'admin'
1793
1882
  end
1794
1883
  end
1795
1884
  ```
@@ -2248,6 +2337,18 @@ params do
2248
2337
  end
2249
2338
  ```
2250
2339
 
2340
+ If documentation isn't needed (for instance, it is an internal API), documentation can be disabled.
2341
+
2342
+ ```ruby
2343
+ class API < Grape::API
2344
+ do_not_document!
2345
+
2346
+ # endpoints...
2347
+ end
2348
+ ```
2349
+
2350
+ In this case, Grape won't create objects related to documentation which are retained in RAM forever.
2351
+
2251
2352
  ## Cookies
2252
2353
 
2253
2354
  You can set, get and delete your cookies very simply using `cookies` method.
@@ -3701,7 +3802,7 @@ Use `rack-test` and define your API as `app`.
3701
3802
  You can test a Grape API with RSpec by making HTTP requests and examining the response.
3702
3803
 
3703
3804
  ```ruby
3704
- require 'spec_helper'
3805
+
3705
3806
 
3706
3807
  describe Twitter::API do
3707
3808
  include Rack::Test::Methods
data/UPGRADING.md CHANGED
@@ -1,6 +1,21 @@
1
1
  Upgrading Grape
2
2
  ===============
3
3
 
4
+ ### Upgrading to >= 1.7.0
5
+
6
+ #### Exceptions renaming
7
+
8
+ The following exceptions has been renamed for consistency through exceptions naming :
9
+
10
+ * `MissingGroupTypeError` => `MissingGroupType`
11
+ * `UnsupportedGroupTypeError` => `UnsupportedGroupType`
12
+
13
+ See [#2227](https://github.com/ruby-grape/grape/pull/2227) for more information.
14
+
15
+ #### Handling Multipart Limit Errors
16
+
17
+ Rack supports a configurable limit on the number of files created from multipart parameters (`Rack::Utils.multipart_part_limit`) and raises an error if params are received that create too many files. If you were handling the Rack error directly, Grape now wraps that error in `Grape::Execeptions::TooManyMultipartFiles`. Additionally, Grape will return a 413 status code if the exception goes unhandled.
18
+
4
19
  ### Upgrading to >= 1.6.0
5
20
 
6
21
  #### Parameter renaming with :as
@@ -101,7 +101,7 @@ module Grape
101
101
  # block passed in. Allows for simple 'before' setups
102
102
  # of settings stack pushes.
103
103
  def nest(*blocks, &block)
104
- blocks.reject!(&:nil?)
104
+ blocks.compact!
105
105
  if blocks.any?
106
106
  evaluate_as_instance_with_configuration(block) if block
107
107
  blocks.each { |b| evaluate_as_instance_with_configuration(b) }
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-types'
4
+
5
+ module Grape
6
+ module DryTypes
7
+ # Call +Dry.Types()+ to add all registered types to +DryTypes+ which is
8
+ # a container in this case. Check documentation for more information
9
+ # https://dry-rb.org/gems/dry-types/1.2/getting-started/
10
+ include Dry.Types()
11
+ end
12
+ end
data/lib/grape/dsl/api.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module API
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  # Blocks can be executed before or after every API call, using `before`, `after`,
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module Configuration
@@ -78,21 +78,6 @@ module Grape
78
78
  route_setting :description, options
79
79
  end
80
80
 
81
- def description_field(field, value = nil)
82
- description = route_setting(:description)
83
- if value
84
- description ||= route_setting(:description, {})
85
- description[field] = value
86
- elsif description
87
- description[field]
88
- end
89
- end
90
-
91
- def unset_description_field(field)
92
- description = route_setting(:description)
93
- description&.delete(field)
94
- end
95
-
96
81
  # Returns an object which configures itself via an instance-context DSL.
97
82
  def desc_container(endpoint_configuration)
98
83
  Module.new do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module Helpers
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
3
  require 'grape/dsl/headers'
5
4
 
6
5
  module Grape
@@ -29,7 +28,7 @@ module Grape
29
28
  # has completed
30
29
  module PostBeforeFilter
31
30
  def declared(passed_params, options = {}, declared_params = nil, params_nested_path = [])
32
- options = options.reverse_merge(include_missing: true, include_parent_namespaces: true)
31
+ options = options.reverse_merge(include_missing: true, include_parent_namespaces: true, evaluate_given: false)
33
32
  declared_params ||= optioned_declared_params(**options)
34
33
 
35
34
  if passed_params.is_a?(Array)
@@ -48,41 +47,46 @@ module Grape
48
47
  end
49
48
 
50
49
  def declared_hash(passed_params, options, declared_params, params_nested_path)
51
- renamed_params = route_setting(:renamed_params) || {}
50
+ declared_params.each_with_object(passed_params.class.new) do |declared_param_attr, memo|
51
+ next if options[:evaluate_given] && !declared_param_attr.scope.attr_meets_dependency?(passed_params)
52
52
 
53
- declared_params.each_with_object(passed_params.class.new) do |declared_param, memo|
54
- if declared_param.is_a?(Hash)
55
- declared_param.each_pair do |declared_parent_param, declared_children_params|
56
- params_nested_path_dup = params_nested_path.dup
57
- params_nested_path_dup << declared_parent_param.to_s
58
- next unless options[:include_missing] || passed_params.key?(declared_parent_param)
53
+ declared_hash_attr(passed_params, options, declared_param_attr.key, params_nested_path, memo)
54
+ end
55
+ end
59
56
 
60
- rename_path = params_nested_path + [declared_parent_param.to_s]
61
- renamed_param_name = renamed_params[rename_path]
57
+ def declared_hash_attr(passed_params, options, declared_param, params_nested_path, memo)
58
+ renamed_params = route_setting(:renamed_params) || {}
59
+ if declared_param.is_a?(Hash)
60
+ declared_param.each_pair do |declared_parent_param, declared_children_params|
61
+ params_nested_path_dup = params_nested_path.dup
62
+ params_nested_path_dup << declared_parent_param.to_s
63
+ next unless options[:include_missing] || passed_params.key?(declared_parent_param)
64
+
65
+ rename_path = params_nested_path + [declared_parent_param.to_s]
66
+ renamed_param_name = renamed_params[rename_path]
62
67
 
63
- memo_key = optioned_param_key(renamed_param_name || declared_parent_param, options)
64
- passed_children_params = passed_params[declared_parent_param] || passed_params.class.new
68
+ memo_key = optioned_param_key(renamed_param_name || declared_parent_param, options)
69
+ passed_children_params = passed_params[declared_parent_param] || passed_params.class.new
65
70
 
66
- memo[memo_key] = handle_passed_param(params_nested_path_dup, passed_children_params.any?) do
67
- declared(passed_children_params, options, declared_children_params, params_nested_path_dup)
68
- end
71
+ memo[memo_key] = handle_passed_param(params_nested_path_dup, passed_children_params.any?) do
72
+ declared(passed_children_params, options, declared_children_params, params_nested_path_dup)
69
73
  end
70
- else
71
- # If it is not a Hash then it does not have children.
72
- # Find its value or set it to nil.
73
- next unless options[:include_missing] || passed_params.key?(declared_param)
74
+ end
75
+ else
76
+ # If it is not a Hash then it does not have children.
77
+ # Find its value or set it to nil.
78
+ return unless options[:include_missing] || passed_params.key?(declared_param)
74
79
 
75
- rename_path = params_nested_path + [declared_param.to_s]
76
- renamed_param_name = renamed_params[rename_path]
80
+ rename_path = params_nested_path + [declared_param.to_s]
81
+ renamed_param_name = renamed_params[rename_path]
77
82
 
78
- memo_key = optioned_param_key(renamed_param_name || declared_param, options)
79
- passed_param = passed_params[declared_param]
83
+ memo_key = optioned_param_key(renamed_param_name || declared_param, options)
84
+ passed_param = passed_params[declared_param]
80
85
 
81
- params_nested_path_dup = params_nested_path.dup
82
- params_nested_path_dup << declared_param.to_s
83
- memo[memo_key] = passed_param || handle_passed_param(params_nested_path_dup) do
84
- passed_param
85
- end
86
+ params_nested_path_dup = params_nested_path.dup
87
+ params_nested_path_dup << declared_param.to_s
88
+ memo[memo_key] = passed_param || handle_passed_param(params_nested_path_dup) do
89
+ passed_param
86
90
  end
87
91
  end
88
92
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module Middleware
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  # Defines DSL methods, meant to be applied to a ParamsScope, which define
@@ -64,7 +62,7 @@ module Grape
64
62
  params_block = named_params.fetch(name) do
65
63
  raise "Params :#{name} not found!"
66
64
  end
67
- instance_exec(options, &params_block)
65
+ instance_exec(**options, &params_block)
68
66
  end
69
67
  end
70
68
  alias use_scope use
@@ -150,8 +148,8 @@ module Grape
150
148
 
151
149
  # check type for optional parameter group
152
150
  if attrs && block
153
- raise Grape::Exceptions::MissingGroupTypeError.new if type.nil?
154
- raise Grape::Exceptions::UnsupportedGroupTypeError.new unless Grape::Validations::Types.group?(type)
151
+ raise Grape::Exceptions::MissingGroupType if type.nil?
152
+ raise Grape::Exceptions::UnsupportedGroupType unless Grape::Validations::Types.group?(type)
155
153
  end
156
154
 
157
155
  if opts[:using]
@@ -219,8 +217,8 @@ module Grape
219
217
  else
220
218
  # @declared_params also includes hashes of options and such, but those
221
219
  # won't be flattened out.
222
- @declared_params.flatten.any? do |declared_param|
223
- first_hash_key_or_param(declared_param) == param
220
+ @declared_params.flatten.any? do |declared_param_attr|
221
+ first_hash_key_or_param(declared_param_attr.key) == param
224
222
  end
225
223
  end
226
224
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module RequestResponse
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module Routing
@@ -79,6 +77,10 @@ module Grape
79
77
  namespace_inheritable(:do_not_route_options, true)
80
78
  end
81
79
 
80
+ def do_not_document!
81
+ namespace_inheritable(:do_not_document, true)
82
+ end
83
+
82
84
  def mount(mounts, *opts)
83
85
  mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair)
84
86
  mounts.each_pair do |app, path|
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  # Keeps track of settings (implemented as key-value pairs, grouped by
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/concern'
4
-
5
3
  module Grape
6
4
  module DSL
7
5
  module Validations
@@ -32,7 +30,6 @@ module Grape
32
30
  unset_namespace_stackable :declared_params
33
31
  unset_namespace_stackable :validations
34
32
  unset_namespace_stackable :params
35
- unset_description_field :params
36
33
  end
37
34
 
38
35
  # Opens a root-level ParamsScope, defining parameter coercions and
@@ -41,18 +38,6 @@ module Grape
41
38
  def params(&block)
42
39
  Grape::Validations::ParamsScope.new(api: self, type: Hash, &block)
43
40
  end
44
-
45
- def document_attribute(names, opts)
46
- setting = description_field(:params)
47
- setting ||= description_field(:params, {})
48
- Array(names).each do |name|
49
- full_name = name[:full_name].to_s
50
- setting[full_name] ||= {}
51
- setting[full_name].merge!(opts)
52
-
53
- namespace_stackable(:params, full_name => opts)
54
- end
55
- end
56
41
  end
57
42
  end
58
43
  end
@@ -21,9 +21,15 @@ module Grape
21
21
  if message.is_a?(Exceptions::ValidationErrors) || message.is_a?(Hash)
22
22
  message
23
23
  else
24
- { error: message }
24
+ { error: ensure_utf8(message) }
25
25
  end
26
26
  end
27
+
28
+ def ensure_utf8(message)
29
+ return message unless message.respond_to? :encode
30
+
31
+ message.encode('UTF-8', invalid: :replace, undef: :replace)
32
+ end
27
33
  end
28
34
  end
29
35
  end
@@ -7,12 +7,12 @@ module Grape
7
7
  BASE_ATTRIBUTES_KEY = 'grape.errors.attributes'
8
8
  FALLBACK_LOCALE = :en
9
9
 
10
- attr_reader :status, :message, :headers
10
+ attr_reader :status, :headers
11
11
 
12
12
  def initialize(status: nil, message: nil, headers: nil, **_options)
13
13
  @status = status
14
- @message = message
15
14
  @headers = headers
15
+ super(message)
16
16
  end
17
17
 
18
18
  def [](index)
@@ -2,10 +2,17 @@
2
2
 
3
3
  module Grape
4
4
  module Exceptions
5
- class MissingGroupTypeError < Base
5
+ class MissingGroupType < Base
6
6
  def initialize
7
7
  super(message: compose_message(:missing_group_type))
8
8
  end
9
9
  end
10
10
  end
11
11
  end
12
+
13
+ Grape::Exceptions::MissingGroupTypeError = Class.new(Grape::Exceptions::MissingGroupType) do
14
+ def initialize(*)
15
+ super
16
+ warn '[DEPRECATION] `Grape::Exceptions::MissingGroupTypeError` is deprecated. Use `Grape::Exceptions::MissingGroupType` instead.'
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Exceptions
5
+ class TooManyMultipartFiles < Base
6
+ def initialize(limit)
7
+ super(message: compose_message(:too_many_multipart_files, limit: limit), status: 413)
8
+ end
9
+ end
10
+ end
11
+ end