grape 1.7.1 → 2.0.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.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/README.md +30 -25
  5. data/UPGRADING.md +35 -0
  6. data/grape.gemspec +3 -6
  7. data/lib/grape/api.rb +2 -2
  8. data/lib/grape/content_types.rb +2 -8
  9. data/lib/grape/dsl/desc.rb +1 -1
  10. data/lib/grape/dsl/inside_route.rb +11 -11
  11. data/lib/grape/dsl/request_response.rb +2 -1
  12. data/lib/grape/dsl/settings.rb +2 -6
  13. data/lib/grape/endpoint.rb +28 -18
  14. data/lib/grape/error_formatter/base.rb +1 -1
  15. data/lib/grape/exceptions/base.rb +2 -2
  16. data/lib/grape/exceptions/missing_group_type.rb +1 -6
  17. data/lib/grape/exceptions/unsupported_group_type.rb +1 -6
  18. data/lib/grape/exceptions/validation_errors.rb +1 -6
  19. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +3 -3
  20. data/lib/grape/extensions/hash.rb +4 -7
  21. data/lib/grape/extensions/hashie/mash.rb +3 -3
  22. data/lib/grape/formatter/serializable_hash.rb +7 -7
  23. data/lib/grape/http/headers.rb +12 -2
  24. data/lib/grape/middleware/auth/base.rb +1 -1
  25. data/lib/grape/middleware/auth/strategies.rb +1 -2
  26. data/lib/grape/middleware/error.rb +5 -5
  27. data/lib/grape/middleware/formatter.rb +6 -6
  28. data/lib/grape/middleware/versioner/header.rb +11 -19
  29. data/lib/grape/railtie.rb +9 -0
  30. data/lib/grape/request.rb +8 -2
  31. data/lib/grape/router/route.rb +1 -3
  32. data/lib/grape/util/lazy_value.rb +3 -11
  33. data/lib/grape/util/strict_hash_configuration.rb +3 -4
  34. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  35. data/lib/grape/validations/params_scope.rb +8 -2
  36. data/lib/grape/validations/single_attribute_iterator.rb +3 -1
  37. data/lib/grape/validations/types/custom_type_coercer.rb +2 -16
  38. data/lib/grape/validations/validators/base.rb +9 -20
  39. data/lib/grape/validations/validators/default_validator.rb +2 -20
  40. data/lib/grape/validations/validators/multiple_params_base.rb +4 -8
  41. data/lib/grape/validations/validators/values_validator.rb +14 -5
  42. data/lib/grape/version.rb +1 -1
  43. data/lib/grape.rb +26 -5
  44. metadata +13 -253
  45. data/lib/grape/config.rb +0 -34
  46. data/lib/grape/extensions/deep_mergeable_hash.rb +0 -21
  47. data/lib/grape/extensions/deep_symbolize_hash.rb +0 -32
  48. data/spec/grape/api/custom_validations_spec.rb +0 -256
  49. data/spec/grape/api/deeply_included_options_spec.rb +0 -56
  50. data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
  51. data/spec/grape/api/documentation_spec.rb +0 -59
  52. data/spec/grape/api/inherited_helpers_spec.rb +0 -114
  53. data/spec/grape/api/instance_spec.rb +0 -103
  54. data/spec/grape/api/invalid_format_spec.rb +0 -45
  55. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
  56. data/spec/grape/api/nested_helpers_spec.rb +0 -50
  57. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
  58. data/spec/grape/api/parameters_modification_spec.rb +0 -41
  59. data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
  60. data/spec/grape/api/recognize_path_spec.rb +0 -21
  61. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
  62. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
  63. data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
  64. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
  65. data/spec/grape/api/shared_helpers_spec.rb +0 -36
  66. data/spec/grape/api_remount_spec.rb +0 -473
  67. data/spec/grape/api_spec.rb +0 -4347
  68. data/spec/grape/config_spec.rb +0 -17
  69. data/spec/grape/dsl/callbacks_spec.rb +0 -45
  70. data/spec/grape/dsl/desc_spec.rb +0 -101
  71. data/spec/grape/dsl/headers_spec.rb +0 -62
  72. data/spec/grape/dsl/helpers_spec.rb +0 -100
  73. data/spec/grape/dsl/inside_route_spec.rb +0 -535
  74. data/spec/grape/dsl/logger_spec.rb +0 -24
  75. data/spec/grape/dsl/middleware_spec.rb +0 -60
  76. data/spec/grape/dsl/parameters_spec.rb +0 -180
  77. data/spec/grape/dsl/request_response_spec.rb +0 -206
  78. data/spec/grape/dsl/routing_spec.rb +0 -275
  79. data/spec/grape/dsl/settings_spec.rb +0 -261
  80. data/spec/grape/dsl/validations_spec.rb +0 -55
  81. data/spec/grape/endpoint/declared_spec.rb +0 -846
  82. data/spec/grape/endpoint_spec.rb +0 -1085
  83. data/spec/grape/entity_spec.rb +0 -336
  84. data/spec/grape/exceptions/base_spec.rb +0 -81
  85. data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -145
  86. data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
  87. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
  88. data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
  89. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
  90. data/spec/grape/exceptions/missing_group_type_spec.rb +0 -21
  91. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
  92. data/spec/grape/exceptions/missing_option_spec.rb +0 -15
  93. data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
  94. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
  95. data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -23
  96. data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
  97. data/spec/grape/exceptions/validation_spec.rb +0 -19
  98. data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
  99. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
  100. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
  101. data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
  102. data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
  103. data/spec/grape/integration/rack_spec.rb +0 -51
  104. data/spec/grape/loading_spec.rb +0 -44
  105. data/spec/grape/middleware/auth/base_spec.rb +0 -31
  106. data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
  107. data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
  108. data/spec/grape/middleware/base_spec.rb +0 -221
  109. data/spec/grape/middleware/error_spec.rb +0 -85
  110. data/spec/grape/middleware/exception_spec.rb +0 -294
  111. data/spec/grape/middleware/formatter_spec.rb +0 -461
  112. data/spec/grape/middleware/globals_spec.rb +0 -30
  113. data/spec/grape/middleware/stack_spec.rb +0 -155
  114. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
  115. data/spec/grape/middleware/versioner/header_spec.rb +0 -345
  116. data/spec/grape/middleware/versioner/param_spec.rb +0 -171
  117. data/spec/grape/middleware/versioner/path_spec.rb +0 -62
  118. data/spec/grape/middleware/versioner_spec.rb +0 -21
  119. data/spec/grape/named_api_spec.rb +0 -19
  120. data/spec/grape/parser_spec.rb +0 -86
  121. data/spec/grape/path_spec.rb +0 -252
  122. data/spec/grape/presenters/presenter_spec.rb +0 -71
  123. data/spec/grape/request_spec.rb +0 -136
  124. data/spec/grape/util/inheritable_setting_spec.rb +0 -242
  125. data/spec/grape/util/inheritable_values_spec.rb +0 -79
  126. data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
  127. data/spec/grape/util/stackable_values_spec.rb +0 -128
  128. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
  129. data/spec/grape/validations/attributes_doc_spec.rb +0 -153
  130. data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
  131. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -40
  132. data/spec/grape/validations/params_scope_spec.rb +0 -1420
  133. data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -57
  134. data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
  135. data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
  136. data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
  137. data/spec/grape/validations/types_spec.rb +0 -111
  138. data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
  139. data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
  140. data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
  141. data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
  142. data/spec/grape/validations/validators/default_spec.rb +0 -463
  143. data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
  144. data/spec/grape/validations/validators/except_values_spec.rb +0 -192
  145. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
  146. data/spec/grape/validations/validators/presence_spec.rb +0 -315
  147. data/spec/grape/validations/validators/regexp_spec.rb +0 -161
  148. data/spec/grape/validations/validators/same_as_spec.rb +0 -57
  149. data/spec/grape/validations/validators/values_spec.rb +0 -696
  150. data/spec/grape/validations/validators/zh-CN.yml +0 -10
  151. data/spec/grape/validations_spec.rb +0 -2029
  152. data/spec/integration/eager_load/eager_load_spec.rb +0 -15
  153. data/spec/integration/multi_json/json_spec.rb +0 -7
  154. data/spec/integration/multi_xml/xml_spec.rb +0 -7
  155. data/spec/shared/versioning_examples.rb +0 -215
  156. data/spec/spec_helper.rb +0 -52
  157. data/spec/support/basic_auth_encode_helpers.rb +0 -11
  158. data/spec/support/chunks.rb +0 -14
  159. data/spec/support/content_type_helpers.rb +0 -15
  160. data/spec/support/endpoint_faker.rb +0 -25
  161. data/spec/support/file_streamer.rb +0 -13
  162. data/spec/support/integer_helpers.rb +0 -13
  163. data/spec/support/versioned_helpers.rb +0 -55
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40277732454d8810e4e96f638da9e6bd4ab818e39ac9c30788791cb4bd429871
4
- data.tar.gz: b075dd96ba3dda6fcd05e6b1c126255b5e206b2d6bb9bf9b52f9cd6ec25a6efc
3
+ metadata.gz: 4983aa4cc8cb0085312902cb28ced60d0e8ff0762821f50027adec6e66f4f75a
4
+ data.tar.gz: 1b22ed94c6e526aa8485f4e27ae4cde775ae424018805544620008b090054c7e
5
5
  SHA512:
6
- metadata.gz: 61d1ef36c90927e08119b6abf57b87fc5317b7b4ac73587d14bc23c9b671e0e76930b89b22d15ec806861f2c60c582647a4f95bc6a1100dca07066be1853d4e6
7
- data.tar.gz: 42a4595d466b2092759dee55ad467a6733e29912b0faaf3abe203c18ab1c84b53b6a1d45868102ac16e6b431254664a6762b3ec0b8e52217c777f99adcf965cc
6
+ metadata.gz: 7680cff51b187ef4f941a8e1596af52ee79b6631da12670e3031eeb79470e2f15a681c3f19406ecdca63e21ad9e2dbcc8362bc4f86c36647940305786f7f082e
7
+ data.tar.gz: 00dc6bd81800ddaf0638ddc8619a6989f3560b38344807a9058bb470c6ecaa29108e52b9104edafdfb1afd4ee70d98c73a9a51db9a6df9081eb42820a2e25773
data/CHANGELOG.md CHANGED
@@ -1,4 +1,40 @@
1
- ### 1.7.1 (2023/05/14)
1
+ ### 2.0.0 (2023/11/11)
2
+
3
+ #### Features
4
+
5
+ * [#2353](https://github.com/ruby-grape/grape/pull/2353): Added Rails 7.1 support - [@ericproulx](https://github.com/ericproulx).
6
+ * [#2355](https://github.com/ruby-grape/grape/pull/2355): Set response headers based on Rack version - [@schinery](https://github.com/schinery).
7
+ * [#2360](https://github.com/ruby-grape/grape/pull/2360): Reduce gem size by removing specs - [@ericproulx](https://github.com/ericproulx).
8
+ * [#2361](https://github.com/ruby-grape/grape/pull/2361): Remove `Rack::Auth::Digest` - [@ninoseki](https://github.com/ninoseki).
9
+
10
+ #### Fixes
11
+
12
+ * [#2364](https://github.com/ruby-grape/grape/pull/2364): Add missing requires - [@ericproulx](https://github.com/ericproulx).
13
+ * [#2366](https://github.com/ruby-grape/grape/pull/2366): Default quality to 1.0 in the `Accept` header when omitted - [@hiddewie](https://github.com/hiddewie).
14
+ * [#2368](https://github.com/ruby-grape/grape/pull/2368): Stripping the internals of `Grape::Endpoint` when `NoMethodError` is raised - [@jcagarcia](https://github.com/jcagarcia).
15
+
16
+ ### 1.8.0 (2023/08/30)
17
+
18
+ #### Features
19
+
20
+ * [#2326](https://github.com/ruby-grape/grape/pull/2326): Use ActiveSupport extensions - [@ericproulx](https://github.com/ericproulx).
21
+ * [#2327](https://github.com/ruby-grape/grape/pull/2327): Use ActiveSupport deprecation - [@ericproulx](https://github.com/ericproulx).
22
+ * [#2330](https://github.com/ruby-grape/grape/pull/2330): Use ActiveSupport inflector - [@ericproulx](https://github.com/ericproulx).
23
+ * [#2331](https://github.com/ruby-grape/grape/pull/2331): Memory optimization when running validators - [@ericproulx](https://github.com/ericproulx).
24
+ * [#2332](https://github.com/ruby-grape/grape/pull/2332): Use ActiveSupport configurable - [@ericproulx](https://github.com/ericproulx).
25
+ * [#2333](https://github.com/ruby-grape/grape/pull/2333): Use custom messages in parameter validation with arity 1 - [@thedevjoao](https://github.com/TheDevJoao).
26
+ * [#2341](https://github.com/ruby-grape/grape/pull/2341): Stop yielding skip value - [@ericproulx](https://github.com/ericproulx).
27
+ * [#2342](https://github.com/ruby-grape/grape/pull/2342): Allow specifying a handler for grape_exceptions - [@mscrivo](https://github.com/mscrivo).
28
+ * [#2338](https://github.com/ruby-grape/grape/pull/2338): Fix unknown validator when using requires/optional with entity - [@mscrivo](https://github.com/mscrivo).
29
+
30
+ #### Fixes
31
+
32
+ * [#2339](https://github.com/ruby-grape/grape/pull/2339): Documentation and specs for remountable configuration in params - [@myxoh](https://github.com/myxoh).
33
+ * [#2328](https://github.com/ruby-grape/grape/pull/2328): Don't cache Class.instance_methods - [@byroot](https://github.com/byroot).
34
+ * [#2337](https://github.com/ruby-grape/grape/pull/2337): Fix: allow custom validators that do not end with _validator - [@ericproulx](https://github.com/ericproulx).
35
+ * [#2346](https://github.com/ruby-grape/grape/pull/2346): Adjust test expectations to conform to rack 3 - [@kbarrette](https://github.com/kbarrette).
36
+
37
+ ## 1.7.1 (2023/05/14)
2
38
 
3
39
  #### Features
4
40
 
data/CONTRIBUTING.md CHANGED
@@ -145,7 +145,7 @@ git push origin my-feature-branch -f
145
145
 
146
146
  #### Check on Your Pull Request
147
147
 
148
- Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
148
+ Go back to your pull request after a few minutes and see whether it passed muster with CI. Everything should look green, otherwise fix issues and amend your commit as described above.
149
149
 
150
150
  #### Be Patient
151
151
 
data/README.md CHANGED
@@ -15,6 +15,7 @@
15
15
  - [Grape for Enterprise](#grape-for-enterprise)
16
16
  - [Installation](#installation)
17
17
  - [Basic Usage](#basic-usage)
18
+ - [Rails 7.1](#rails-71)
18
19
  - [Mounting](#mounting)
19
20
  - [All](#all)
20
21
  - [Rack](#rack)
@@ -114,7 +115,7 @@
114
115
  - [Active Model Serializers](#active-model-serializers)
115
116
  - [Sending Raw or No Data](#sending-raw-or-no-data)
116
117
  - [Authentication](#authentication)
117
- - [Basic and Digest Auth](#basic-and-digest-auth)
118
+ - [Basic Auth](#basic-auth)
118
119
  - [Register custom middleware for authentication](#register-custom-middleware-for-authentication)
119
120
  - [Describing and Inspecting an API](#describing-and-inspecting-an-api)
120
121
  - [Current Route and Endpoint](#current-route-and-endpoint)
@@ -159,9 +160,10 @@ content negotiation, versioning and much more.
159
160
 
160
161
  ## Stable Release
161
162
 
162
- You're reading the documentation for the stable release of Grape, 1.7.1.
163
+ You're reading the documentation for the stable release of Grape, **2.0.0**.
163
164
  Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
164
165
 
166
+
165
167
  ## Project Resources
166
168
 
167
169
  * [Grape Website](http://www.ruby-grape.org)
@@ -177,7 +179,7 @@ The maintainers of Grape are working with Tidelift to deliver commercial support
177
179
 
178
180
  ## Installation
179
181
 
180
- Ruby 2.4 or newer is required.
182
+ Ruby 2.6 or newer is required.
181
183
 
182
184
  Grape is available as a gem, to install it run:
183
185
 
@@ -266,6 +268,10 @@ module Twitter
266
268
  end
267
269
  ```
268
270
 
271
+ ## Rails 7.1
272
+
273
+ Grape's [deprecator](https://api.rubyonrails.org/v7.1.0/classes/ActiveSupport/Deprecation.html) will be added to your application's deprecators [automatically](lib/grape/railtie.rb) as `:grape`, so that your application's configuration can be applied to it.
274
+
269
275
  ## Mounting
270
276
 
271
277
  ### All
@@ -524,15 +530,15 @@ end
524
530
  ```ruby
525
531
  class BasicAPI < Grape::API
526
532
  desc 'Statuses index' do
527
- params: mounted { configuration[:entity] || API::Entities::Status }.documentation
533
+ params: (configuration[:entity] || API::Entities::Status).documentation
528
534
  end
529
535
  params do
530
- requires :all, using: mounted { configuration[:entity] || API::Entities::Status }.documentation
536
+ requires :all, using: (configuration[:entity] || API::Entities::Status).documentation
531
537
  end
532
538
  get '/statuses' do
533
539
  statuses = Status.all
534
540
  type = current_user.admin? ? :full : :default
535
- present statuses, with: mounted { configuration[:entity] || API::Entities::Status }, type: type
541
+ present statuses, with: (configuration[:entity] || API::Entities::Status), type: type
536
542
  end
537
543
  end
538
544
 
@@ -589,6 +595,10 @@ When an invalid `Accept` header is supplied, a `406 Not Acceptable` error is ret
589
595
  option is set to `false`. Otherwise a `404 Not Found` error is returned by Rack if no other route
590
596
  matches.
591
597
 
598
+ Grape will evaluate the relative quality preference included in Accept headers and default to a quality of 1.0 when omitted. In the following example a Grape API that supports XML and JSON in that order will return JSON:
599
+
600
+ curl -H "Accept: text/xml;q=0.8, application/json;q=0.9" localhost:1234/resource
601
+
592
602
  ### Accept-Version Header
593
603
 
594
604
  ```ruby
@@ -1593,7 +1603,7 @@ Note endless ranges are also supported with ActiveSupport >= 6.0, but they requi
1593
1603
  ```ruby
1594
1604
  params do
1595
1605
  requires :minimum, type: Integer, values: 10..
1596
- optional :maximum, type: Integer, values: ..10
1606
+ optional :maximum, type: Integer, values: ..10
1597
1607
  end
1598
1608
  ```
1599
1609
 
@@ -2123,8 +2133,9 @@ curl -H "secret_PassWord: swordfish" ...
2123
2133
 
2124
2134
  The header name will have been normalized for you.
2125
2135
 
2126
- - In the `header` helper names will be coerced into a capitalized kebab case.
2127
- - In the `env` collection they appear in all uppercase, in snake case, and prefixed with 'HTTP_'.
2136
+ - In the `header` helper names will be coerced into a downcased kebab case as `secret-password` if using Rack 3.
2137
+ - In the `header` helper names will be coerced into a capitalized kebab case as `Secret-PassWord` if using Rack < 3.
2138
+ - In the `env` collection they appear in all uppercase, in snake case, and prefixed with 'HTTP_' as `HTTP_SECRET_PASSWORD`
2128
2139
 
2129
2140
  The header name will have been normalized per HTTP standards defined in [RFC2616 Section 4.2](https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2) regardless of what is being sent by a client.
2130
2141
 
@@ -2624,6 +2635,14 @@ class Twitter::API < Grape::API
2624
2635
  end
2625
2636
  ```
2626
2637
 
2638
+ If you want to customize the shape of grape exceptions returned to the user, to match your `:all` handler for example, you can pass a block to `rescue_from :grape_exceptions`.
2639
+
2640
+ ```ruby
2641
+ rescue_from :grape_exceptions do |e|
2642
+ error!(e, e.status)
2643
+ end
2644
+ ```
2645
+
2627
2646
  You can also rescue specific exceptions.
2628
2647
 
2629
2648
  ```ruby
@@ -3406,9 +3425,9 @@ end
3406
3425
 
3407
3426
  ## Authentication
3408
3427
 
3409
- ### Basic and Digest Auth
3428
+ ### Basic Auth
3410
3429
 
3411
- Grape has built-in Basic and Digest authentication (the given `block`
3430
+ Grape has built-in Basic authentication (the given `block`
3412
3431
  is executed in the context of the current `Endpoint`). Authentication
3413
3432
  applies to the current namespace and any children, but not parents.
3414
3433
 
@@ -3419,20 +3438,6 @@ http_basic do |username, password|
3419
3438
  end
3420
3439
  ```
3421
3440
 
3422
- Digest auth supports clear-text passwords and password hashes.
3423
-
3424
- ```ruby
3425
- http_digest({ realm: 'Test Api', opaque: 'app secret' }) do |username|
3426
- # lookup the user's password here
3427
- end
3428
- ```
3429
-
3430
- ```ruby
3431
- http_digest(realm: { realm: 'Test Api', opaque: 'app secret', passwords_hashed: true }) do |username|
3432
- # lookup the user's password hash here
3433
- end
3434
- ```
3435
-
3436
3441
  ### Register custom middleware for authentication
3437
3442
 
3438
3443
  Grape can use custom Middleware for authentication. How to implement these
data/UPGRADING.md CHANGED
@@ -1,6 +1,41 @@
1
1
  Upgrading Grape
2
2
  ===============
3
3
 
4
+ ### Upgrading to >= 2.0.0
5
+
6
+ #### Headers
7
+
8
+ As per [rack/rack#1592](https://github.com/rack/rack/issues/1592) Rack 3 is following the HTTP/2+ semantics which require header names to be lower case. To avoid compatibility issues, starting with Grape 1.9.0, headers will be cased based on what version of Rack you are using.
9
+
10
+ Given this request:
11
+
12
+ ```shell
13
+ curl -H "Content-Type: application/json" -H "Secret-Password: foo" ...
14
+ ```
15
+
16
+ If you are using Rack 3 in your application then the headers will be set to:
17
+
18
+ ```ruby
19
+ { "content-type" => "application/json", "secret-password" => "foo"}
20
+ ```
21
+
22
+ This means if you are checking for header values in your application, you would need to change your code to use downcased keys.
23
+
24
+ ```ruby
25
+ get do
26
+ # This would use headers['Secret-Password'] in Rack < 3
27
+ error!('Unauthorized', 401) unless headers['secret-password'] == 'swordfish'
28
+ end
29
+ ```
30
+
31
+ See [#2355](https://github.com/ruby-grape/grape/pull/2355) for more information.
32
+
33
+ #### Digest auth deprecation
34
+
35
+ Digest auth has been removed along with the deprecation of `Rack::Auth::Digest` in Rack 3.
36
+
37
+ See [#2294](https://github.com/ruby-grape/grape/issues/2294) for more information.
38
+
4
39
  ### Upgrading to >= 1.7.0
5
40
 
6
41
  #### Exceptions renaming
data/grape.gemspec CHANGED
@@ -20,17 +20,14 @@ Gem::Specification.new do |s|
20
20
  'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}"
21
21
  }
22
22
 
23
- s.add_runtime_dependency 'activesupport'
23
+ s.add_runtime_dependency 'activesupport', '>= 5'
24
24
  s.add_runtime_dependency 'builder'
25
25
  s.add_runtime_dependency 'dry-types', '>= 1.1'
26
26
  s.add_runtime_dependency 'mustermann-grape', '~> 1.0.0'
27
- s.add_runtime_dependency 'rack', '>= 1.3.0', '< 3'
27
+ s.add_runtime_dependency 'rack', '>= 1.3.0'
28
28
  s.add_runtime_dependency 'rack-accept'
29
29
 
30
- s.files = %w[CHANGELOG.md CONTRIBUTING.md README.md grape.png UPGRADING.md LICENSE]
31
- s.files += %w[grape.gemspec]
32
- s.files += Dir['lib/**/*']
33
- s.test_files = Dir['spec/**/*']
30
+ s.files = Dir['lib/**/*', 'CHANGELOG.md', 'CONTRIBUTING.md', 'README.md', 'grape.png', 'UPGRADING.md', 'LICENSE', 'grape.gemspec']
34
31
  s.require_paths = ['lib']
35
32
  s.required_ruby_version = '>= 2.6.0'
36
33
  end
data/lib/grape/api.rb CHANGED
@@ -8,7 +8,7 @@ module Grape
8
8
  # should subclass this class in order to build an API.
9
9
  class API
10
10
  # Class methods that we want to call on the API rather than on the API object
11
- NON_OVERRIDABLE = (Class.new.methods + %i[call call! configuration compile! inherited]).freeze
11
+ NON_OVERRIDABLE = %i[call call! configuration compile! inherited].freeze
12
12
 
13
13
  class Boolean
14
14
  def self.build(val)
@@ -50,7 +50,7 @@ module Grape
50
50
 
51
51
  # Redefines all methods so that are forwarded to add_setup and be recorded
52
52
  def override_all_methods!
53
- (base_instance.methods - NON_OVERRIDABLE).each do |method_override|
53
+ (base_instance.methods - Class.methods - NON_OVERRIDABLE).each do |method_override|
54
54
  define_singleton_method(method_override) do |*args, &block|
55
55
  add_setup(method_override, *args, &block)
56
56
  end
@@ -17,17 +17,11 @@ module Grape
17
17
 
18
18
  class << self
19
19
  def content_types_for_settings(settings)
20
- return if settings.blank?
21
-
22
- settings.each_with_object({}) { |value, result| result.merge!(value) }
20
+ settings&.inject(:merge!)
23
21
  end
24
22
 
25
23
  def content_types_for(from_settings)
26
- if from_settings.present?
27
- from_settings
28
- else
29
- Grape::ContentTypes::CONTENT_TYPES.merge(default_elements)
30
- end
24
+ from_settings.presence || Grape::ContentTypes::CONTENT_TYPES.merge(default_elements)
31
25
  end
32
26
  end
33
27
  end
@@ -68,7 +68,7 @@ module Grape
68
68
  end
69
69
 
70
70
  config_class.configure(&config_block)
71
- warn '[DEPRECATION] Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.' unless options.empty?
71
+ Grape.deprecator.warn('Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.') if options.any?
72
72
  options = config_class.settings
73
73
  else
74
74
  options = options.merge(description: description)
@@ -103,7 +103,7 @@ module Grape
103
103
 
104
104
  if type == 'Hash' && !has_children
105
105
  {}
106
- elsif type == 'Array' || (type&.start_with?('[') && !type&.include?(','))
106
+ elsif type == 'Array' || (type&.start_with?('[') && type&.exclude?(','))
107
107
  []
108
108
  elsif type == 'Set' || type&.start_with?('#<Set')
109
109
  Set.new
@@ -185,7 +185,7 @@ module Grape
185
185
  status 302
186
186
  body_message ||= "This resource has been moved temporarily to #{url}."
187
187
  end
188
- header 'Location', url
188
+ header Grape::Http::Headers::LOCATION, url
189
189
  content_type 'text/plain'
190
190
  body body_message
191
191
  end
@@ -224,9 +224,9 @@ module Grape
224
224
  # Set response content-type
225
225
  def content_type(val = nil)
226
226
  if val
227
- header(Grape::Http::Headers::CONTENT_TYPE, val)
227
+ header(Rack::CONTENT_TYPE, val)
228
228
  else
229
- header[Grape::Http::Headers::CONTENT_TYPE]
229
+ header[Rack::CONTENT_TYPE]
230
230
  end
231
231
  end
232
232
 
@@ -280,13 +280,13 @@ module Grape
280
280
  # Deprecated method to send files to the client. Use `sendfile` or `stream`
281
281
  def file(value = nil)
282
282
  if value.is_a?(String)
283
- warn '[DEPRECATION] Use sendfile or stream to send files.'
283
+ Grape.deprecator.warn('Use sendfile or stream to send files.')
284
284
  sendfile(value)
285
285
  elsif !value.is_a?(NilClass)
286
- warn '[DEPRECATION] Use stream to use a Stream object.'
286
+ Grape.deprecator.warn('Use stream to use a Stream object.')
287
287
  stream(value)
288
288
  else
289
- warn '[DEPRECATION] Use sendfile or stream to send files.'
289
+ Grape.deprecator.warn('Use sendfile or stream to send files.')
290
290
  sendfile
291
291
  end
292
292
  end
@@ -328,9 +328,9 @@ module Grape
328
328
  def stream(value = nil)
329
329
  return if value.nil? && @stream.nil?
330
330
 
331
- header 'Content-Length', nil
332
- header 'Transfer-Encoding', nil
333
- header 'Cache-Control', 'no-cache' # Skips ETag generation (reading the response up front)
331
+ header Rack::CONTENT_LENGTH, nil
332
+ header Grape::Http::Headers::TRANSFER_ENCODING, nil
333
+ header Rack::CACHE_CONTROL, 'no-cache' # Skips ETag generation (reading the response up front)
334
334
  if value.is_a?(String)
335
335
  file_body = Grape::ServeStream::FileBody.new(value)
336
336
  @stream = Grape::ServeStream::StreamResponse.new(file_body)
@@ -433,7 +433,7 @@ module Grape
433
433
  # the given entity_class.
434
434
  def entity_representation_for(entity_class, object, options)
435
435
  embeds = { env: env }
436
- embeds[:version] = env[Grape::Env::API_VERSION] if env[Grape::Env::API_VERSION]
436
+ embeds[:version] = env[Grape::Env::API_VERSION] if env.key?(Grape::Env::API_VERSION)
437
437
  entity_class.represent(object, **embeds.merge(options))
438
438
  end
439
439
  end
@@ -112,10 +112,11 @@ module Grape
112
112
 
113
113
  if args.include?(:all)
114
114
  namespace_inheritable(:rescue_all, true)
115
- namespace_inheritable :all_rescue_handler, handler
115
+ namespace_inheritable(:all_rescue_handler, handler)
116
116
  elsif args.include?(:grape_exceptions)
117
117
  namespace_inheritable(:rescue_all, true)
118
118
  namespace_inheritable(:rescue_grape_exceptions, true)
119
+ namespace_inheritable(:grape_exceptions_rescue_handler, handler)
119
120
  else
120
121
  handler_type =
121
122
  case options[:rescue_subclasses]
@@ -109,13 +109,9 @@ module Grape
109
109
  settings = get_or_set :namespace_reverse_stackable, key, nil
110
110
  return if settings.blank?
111
111
 
112
- result = {}
113
- settings.each do |setting|
114
- setting.each do |field, value|
115
- result[field] ||= value
116
- end
112
+ settings.each_with_object({}) do |setting, result|
113
+ result.merge!(setting) { |_k, s1, _s2| s1 }
117
114
  end
118
- result
119
115
  end
120
116
 
121
117
  # (see #unset_global_setting)
@@ -171,10 +171,9 @@ module Grape
171
171
  end
172
172
 
173
173
  def prepare_routes_requirements
174
- endpoint_requirements = options[:route_options][:requirements] || {}
175
- all_requirements = (namespace_stackable(:namespace).map(&:requirements) << endpoint_requirements)
176
- all_requirements.reduce({}) do |base_requirements, single_requirements|
177
- base_requirements.merge!(single_requirements)
174
+ {}.merge!(*namespace_stackable(:namespace).map(&:requirements)).tap do |requirements|
175
+ endpoint_requirements = options.dig(:route_options, :requirements)
176
+ requirements.merge!(endpoint_requirements) if endpoint_requirements
178
177
  end
179
178
  end
180
179
 
@@ -251,7 +250,7 @@ module Grape
251
250
  if (allowed_methods = env[Grape::Env::GRAPE_ALLOWED_METHODS])
252
251
  raise Grape::Exceptions::MethodNotAllowed.new(header.merge('Allow' => allowed_methods)) unless options?
253
252
 
254
- header 'Allow', allowed_methods
253
+ header Grape::Http::Headers::ALLOW, allowed_methods
255
254
  response_object = ''
256
255
  status 204
257
256
  else
@@ -293,7 +292,8 @@ module Grape
293
292
  rescue_options: namespace_stackable_with_hash(:rescue_options) || {},
294
293
  rescue_handlers: namespace_reverse_stackable_with_hash(:rescue_handlers) || {},
295
294
  base_only_rescue_handlers: namespace_stackable_with_hash(:base_only_rescue_handlers) || {},
296
- all_rescue_handler: namespace_inheritable(:all_rescue_handler)
295
+ all_rescue_handler: namespace_inheritable(:all_rescue_handler),
296
+ grape_exceptions_rescue_handler: namespace_inheritable(:grape_exceptions_rescue_handler)
297
297
 
298
298
  stack.concat namespace_stackable(:middleware)
299
299
 
@@ -318,8 +318,8 @@ module Grape
318
318
  end
319
319
 
320
320
  def build_helpers
321
- helpers = namespace_stackable(:helpers) || []
322
- Module.new { helpers.each { |mod_to_include| include mod_to_include } }
321
+ helpers = namespace_stackable(:helpers)
322
+ Module.new { helpers&.each { |mod_to_include| include mod_to_include } }
323
323
  end
324
324
 
325
325
  private :build_stack, :build_helpers
@@ -345,11 +345,9 @@ module Grape
345
345
  end
346
346
  end
347
347
 
348
- def run_validators(validator_factories, request)
348
+ def run_validators(validators, request)
349
349
  validation_errors = []
350
350
 
351
- validators = validator_factories.map { |options| Grape::Validations::ValidatorFactory.create_validator(**options) }
352
-
353
351
  ActiveSupport::Notifications.instrument('endpoint_run_validators.grape', endpoint: self, validators: validators, request: request) do
354
352
  validators.each do |validator|
355
353
  validator.validate(request)
@@ -367,39 +365,51 @@ module Grape
367
365
 
368
366
  def run_filters(filters, type = :other)
369
367
  ActiveSupport::Notifications.instrument('endpoint_run_filters.grape', endpoint: self, filters: filters, type: type) do
370
- (filters || []).each { |filter| instance_eval(&filter) }
368
+ filters&.each { |filter| instance_eval(&filter) }
371
369
  end
372
370
  post_extension = DSL::InsideRoute.post_filter_methods(type)
373
371
  extend post_extension if post_extension
374
372
  end
375
373
 
376
374
  def befores
377
- namespace_stackable(:befores) || []
375
+ namespace_stackable(:befores)
378
376
  end
379
377
 
380
378
  def before_validations
381
- namespace_stackable(:before_validations) || []
379
+ namespace_stackable(:before_validations)
382
380
  end
383
381
 
384
382
  def after_validations
385
- namespace_stackable(:after_validations) || []
383
+ namespace_stackable(:after_validations)
386
384
  end
387
385
 
388
386
  def afters
389
- namespace_stackable(:afters) || []
387
+ namespace_stackable(:afters)
390
388
  end
391
389
 
392
390
  def finallies
393
- namespace_stackable(:finallies) || []
391
+ namespace_stackable(:finallies)
394
392
  end
395
393
 
396
394
  def validations
397
- route_setting(:saved_validations) || []
395
+ return enum_for(:validations) unless block_given?
396
+
397
+ route_setting(:saved_validations)&.each do |saved_validation|
398
+ yield Grape::Validations::ValidatorFactory.create_validator(**saved_validation)
399
+ end
398
400
  end
399
401
 
400
402
  def options?
401
403
  options[:options_route_enabled] &&
402
404
  env[Grape::Http::Headers::REQUEST_METHOD] == Grape::Http::Headers::OPTIONS
403
405
  end
406
+
407
+ def method_missing(name, *_args)
408
+ raise NoMethodError.new("undefined method `#{name}' for #{self.class} in `#{route.origin}' endpoint")
409
+ end
410
+
411
+ def respond_to_missing?(method_name, include_private = false)
412
+ super
413
+ end
404
414
  end
405
415
  end
@@ -27,7 +27,7 @@ module Grape
27
27
 
28
28
  if presenter
29
29
  embeds = { env: env }
30
- embeds[:version] = env[Grape::Env::API_VERSION] if env[Grape::Env::API_VERSION]
30
+ embeds[:version] = env[Grape::Env::API_VERSION] if env.key?(Grape::Env::API_VERSION)
31
31
  presented_message = presenter.represent(presented_message, embeds).serializable_hash
32
32
  end
33
33
 
@@ -73,11 +73,11 @@ module Grape
73
73
  options = options.dup
74
74
  options[:default] &&= options[:default].to_s
75
75
  message = ::I18n.translate(key, **options)
76
- message.present? ? message : fallback_message(key, **options)
76
+ message.presence || fallback_message(key, **options)
77
77
  end
78
78
 
79
79
  def fallback_message(key, **options)
80
- if ::I18n.enforce_available_locales && !::I18n.available_locales.include?(FALLBACK_LOCALE)
80
+ if ::I18n.enforce_available_locales && ::I18n.available_locales.exclude?(FALLBACK_LOCALE)
81
81
  key
82
82
  else
83
83
  ::I18n.translate(key, locale: FALLBACK_LOCALE, **options)
@@ -10,9 +10,4 @@ module Grape
10
10
  end
11
11
  end
12
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
13
+ Grape::Exceptions::MissingGroupTypeError = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Grape::Exceptions::MissingGroupTypeError', 'Grape::Exceptions::MissingGroupType', Grape.deprecator)
@@ -10,9 +10,4 @@ module Grape
10
10
  end
11
11
  end
12
12
 
13
- Grape::Exceptions::UnsupportedGroupTypeError = Class.new(Grape::Exceptions::UnsupportedGroupType) do
14
- def initialize(*)
15
- super
16
- warn '[DEPRECATION] `Grape::Exceptions::UnsupportedGroupTypeError` is deprecated. Use `Grape::Exceptions::UnsupportedGroupType` instead.'
17
- end
18
- end
13
+ Grape::Exceptions::UnsupportedGroupTypeError = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Grape::Exceptions::UnsupportedGroupTypeError', 'Grape::Exceptions::UnsupportedGroupType', Grape.deprecator)
@@ -13,12 +13,7 @@ module Grape
13
13
  attr_reader :errors
14
14
 
15
15
  def initialize(errors: [], headers: {}, **_options)
16
- @errors = {}
17
- errors.each do |validation_error|
18
- @errors[validation_error.params] ||= []
19
- @errors[validation_error.params] << validation_error
20
- end
21
-
16
+ @errors = errors.group_by(&:params)
22
17
  super message: full_messages.join(', '), status: 400, headers: headers
23
18
  end
24
19
 
@@ -16,9 +16,9 @@ module Grape
16
16
  end
17
17
 
18
18
  def build_params
19
- params = ::ActiveSupport::HashWithIndifferentAccess.new(rack_params)
20
- params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
21
- params
19
+ ::ActiveSupport::HashWithIndifferentAccess.new(rack_params).tap do |params|
20
+ params.deep_merge!(grape_routing_args) if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
21
+ end
22
22
  end
23
23
  end
24
24
  end
@@ -11,13 +11,10 @@ module Grape
11
11
  end
12
12
 
13
13
  def build_params
14
- params = Grape::Extensions::DeepMergeableHash[rack_params]
15
- params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
16
- post_process_params(params)
17
- end
18
-
19
- def post_process_params(params)
20
- Grape::Extensions::DeepSymbolizeHash.deep_symbolize_keys_in(params)
14
+ rack_params.deep_dup.tap do |params|
15
+ params.deep_merge!(grape_routing_args) if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
16
+ params.deep_symbolize_keys!
17
+ end
21
18
  end
22
19
  end
23
20
  end
@@ -15,9 +15,9 @@ module Grape
15
15
  end
16
16
 
17
17
  def build_params
18
- params = ::Hashie::Mash.new(rack_params)
19
- params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
20
- params
18
+ ::Hashie::Mash.new(rack_params).tap do |params|
19
+ params.deep_merge!(grape_routing_args) if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
20
+ end
21
21
  end
22
22
  end
23
23
  end