grape 1.7.1 → 2.0.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 +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