grape 2.4.0 → 3.2.1

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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +109 -0
  3. data/CONTRIBUTING.md +2 -10
  4. data/README.md +137 -181
  5. data/UPGRADING.md +154 -0
  6. data/grape.gemspec +4 -4
  7. data/lib/grape/api/instance.rb +51 -104
  8. data/lib/grape/api.rb +29 -42
  9. data/lib/grape/content_types.rb +1 -4
  10. data/lib/grape/declared_params_handler.rb +118 -0
  11. data/lib/grape/dry_types.rb +48 -4
  12. data/lib/grape/dsl/callbacks.rb +8 -58
  13. data/lib/grape/dsl/declared.rb +35 -0
  14. data/lib/grape/dsl/desc.rb +8 -67
  15. data/lib/grape/dsl/helpers.rb +59 -64
  16. data/lib/grape/dsl/inside_route.rb +28 -189
  17. data/lib/grape/dsl/logger.rb +3 -6
  18. data/lib/grape/dsl/middleware.rb +22 -40
  19. data/lib/grape/dsl/parameters.rb +24 -51
  20. data/lib/grape/dsl/request_response.rb +136 -139
  21. data/lib/grape/dsl/routing.rb +240 -200
  22. data/lib/grape/dsl/settings.rb +23 -135
  23. data/lib/grape/dsl/validations.rb +38 -44
  24. data/lib/grape/endpoint.rb +169 -205
  25. data/lib/grape/error_formatter/base.rb +4 -2
  26. data/lib/grape/exceptions/base.rb +19 -45
  27. data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
  28. data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
  29. data/lib/grape/exceptions/invalid_formatter.rb +1 -1
  30. data/lib/grape/exceptions/invalid_message_body.rb +1 -1
  31. data/lib/grape/exceptions/invalid_version_header.rb +1 -1
  32. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
  33. data/lib/grape/exceptions/method_not_allowed.rb +1 -1
  34. data/lib/grape/exceptions/missing_group_type.rb +0 -2
  35. data/lib/grape/exceptions/missing_mime_type.rb +1 -1
  36. data/lib/grape/exceptions/request_error.rb +11 -0
  37. data/lib/grape/exceptions/unknown_auth_strategy.rb +1 -1
  38. data/lib/grape/exceptions/unknown_parameter.rb +1 -1
  39. data/lib/grape/exceptions/unknown_params_builder.rb +1 -1
  40. data/lib/grape/exceptions/unknown_validator.rb +1 -1
  41. data/lib/grape/exceptions/unsupported_group_type.rb +0 -2
  42. data/lib/grape/exceptions/validation.rb +7 -4
  43. data/lib/grape/exceptions/validation_errors.rb +13 -7
  44. data/lib/grape/locale/en.yml +0 -5
  45. data/lib/grape/middleware/auth/base.rb +2 -0
  46. data/lib/grape/middleware/auth/dsl.rb +9 -10
  47. data/lib/grape/middleware/base.rb +6 -4
  48. data/lib/grape/middleware/error.rb +4 -14
  49. data/lib/grape/middleware/formatter.rb +11 -7
  50. data/lib/grape/middleware/stack.rb +3 -2
  51. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -3
  52. data/lib/grape/middleware/versioner/base.rb +42 -40
  53. data/lib/grape/middleware/versioner/header.rb +2 -18
  54. data/lib/grape/middleware/versioner/param.rb +2 -2
  55. data/lib/grape/middleware/versioner/path.rb +2 -2
  56. data/lib/grape/namespace.rb +15 -8
  57. data/lib/grape/params_builder/base.rb +2 -0
  58. data/lib/grape/params_builder.rb +2 -19
  59. data/lib/grape/request.rb +2 -10
  60. data/lib/grape/router/base_route.rb +14 -5
  61. data/lib/grape/router/greedy_route.rb +11 -5
  62. data/lib/grape/router/pattern.rb +6 -20
  63. data/lib/grape/router/route.rb +7 -11
  64. data/lib/grape/router.rb +42 -65
  65. data/lib/grape/util/api_description.rb +58 -0
  66. data/lib/grape/util/base_inheritable.rb +5 -2
  67. data/lib/grape/util/cache.rb +1 -0
  68. data/lib/grape/util/deep_freeze.rb +35 -0
  69. data/lib/grape/util/inheritable_setting.rb +8 -1
  70. data/lib/grape/util/media_type.rb +2 -2
  71. data/lib/grape/util/registry.rb +1 -1
  72. data/lib/grape/util/translation.rb +42 -0
  73. data/lib/grape/validations/attributes_iterator.rb +35 -20
  74. data/lib/grape/validations/contract_scope.rb +2 -8
  75. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  76. data/lib/grape/validations/param_scope_tracker.rb +57 -0
  77. data/lib/grape/validations/params_documentation.rb +50 -0
  78. data/lib/grape/validations/params_scope.rb +147 -156
  79. data/lib/grape/validations/single_attribute_iterator.rb +2 -2
  80. data/lib/grape/validations/types/array_coercer.rb +2 -3
  81. data/lib/grape/validations/types/dry_type_coercer.rb +4 -11
  82. data/lib/grape/validations/types/primitive_coercer.rb +1 -28
  83. data/lib/grape/validations/types.rb +10 -25
  84. data/lib/grape/validations/validators/all_or_none_of_validator.rb +6 -3
  85. data/lib/grape/validations/validators/allow_blank_validator.rb +10 -5
  86. data/lib/grape/validations/validators/at_least_one_of_validator.rb +5 -2
  87. data/lib/grape/validations/validators/base.rb +95 -25
  88. data/lib/grape/validations/validators/coerce_validator.rb +15 -35
  89. data/lib/grape/validations/validators/contract_scope_validator.rb +9 -5
  90. data/lib/grape/validations/validators/default_validator.rb +12 -18
  91. data/lib/grape/validations/validators/exactly_one_of_validator.rb +10 -3
  92. data/lib/grape/validations/validators/except_values_validator.rb +13 -4
  93. data/lib/grape/validations/validators/length_validator.rb +21 -22
  94. data/lib/grape/validations/validators/multiple_params_base.rb +5 -5
  95. data/lib/grape/validations/validators/{mutual_exclusion_validator.rb → mutually_exclusive_validator.rb} +4 -2
  96. data/lib/grape/validations/validators/presence_validator.rb +4 -2
  97. data/lib/grape/validations/validators/regexp_validator.rb +11 -3
  98. data/lib/grape/validations/validators/same_as_validator.rb +6 -15
  99. data/lib/grape/validations/validators/values_validator.rb +29 -21
  100. data/lib/grape/version.rb +1 -1
  101. data/lib/grape.rb +29 -23
  102. metadata +31 -26
  103. data/lib/grape/api/helpers.rb +0 -9
  104. data/lib/grape/dsl/api.rb +0 -17
  105. data/lib/grape/dsl/configuration.rb +0 -15
  106. data/lib/grape/exceptions/conflicting_types.rb +0 -11
  107. data/lib/grape/exceptions/empty_message_body.rb +0 -11
  108. data/lib/grape/exceptions/invalid_parameters.rb +0 -11
  109. data/lib/grape/exceptions/missing_option.rb +0 -11
  110. data/lib/grape/exceptions/too_deep_parameters.rb +0 -11
  111. data/lib/grape/exceptions/too_many_multipart_files.rb +0 -11
  112. data/lib/grape/exceptions/unknown_options.rb +0 -11
  113. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +0 -24
  114. data/lib/grape/extensions/hash.rb +0 -27
  115. data/lib/grape/extensions/hashie/mash.rb +0 -24
  116. data/lib/grape/types/invalid_value.rb +0 -8
  117. data/lib/grape/util/strict_hash_configuration.rb +0 -108
  118. data/lib/grape/validations/attributes_doc.rb +0 -60
  119. data/lib/grape/validations/validator_factory.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83e82bddb3698a0f659d7c58edcb20c2d7edd44cce6e78f31139a2cf3452da0e
4
- data.tar.gz: d47076d4e1b7445029b7695b5cfcb0ddebf72a1106743817eb583f79e636c8fc
3
+ metadata.gz: 81a1d1ef86854a9cd7fe4d60a1207fba921bdee9f6fd53e2f9e83c648e85c2e0
4
+ data.tar.gz: 7a19d899e17d65141c9ce69a10e518a8d7ccec01cd1239f7c2557b77a4084ad4
5
5
  SHA512:
6
- metadata.gz: a22fbee812a61d12aa8ca151cc53835df146d840173fc92d9bb4ae049b5b14a70f6d399fcd06440167312af7bd60116e8382f21424a7c8b494b0251a82e7cea5
7
- data.tar.gz: cd3d6d737305696db1cb703639dcdc3d7a6a4e32c02a25fd3942bef3e91529a8acaf11bb5cd4039b108ef2c908461c233a54207d2c4f528959fd944afeac0b22
6
+ metadata.gz: b9ffeac5636c40b3ed53323c26eb7c5f525be4bf8268b85e4e8851cbbf2d3118e8ddc7387f81f06ef1342396cfe3af9562b5920e38548b5bf1de00536c9b136c
7
+ data.tar.gz: 7fed8d88f46a2d5af508fc0ab5e68333c3b2bde482b9e7b393ea12f2e38bb08b6d3fc9bd8c9f9dfe08adccc2816f2faaf89810d16138f803d1b009b1d0940f38
data/CHANGELOG.md CHANGED
@@ -1,3 +1,111 @@
1
+ ### 3.2.1 (2026-04-16)
2
+
3
+ #### Fixes
4
+ * [#2680](https://github.com/ruby-grape/grape/pull/2680): Restore public `schema` reader on ContractScope validator - [@ericproulx](https://github.com/ericproulx).
5
+
6
+ ### 3.2.0 (2026-04-08)
7
+
8
+ #### Features
9
+
10
+ * [#2662](https://github.com/ruby-grape/grape/pull/2662): Extract `Grape::Util::Translation` for shared I18n fallback logic - [@ericproulx](https://github.com/ericproulx).
11
+ * [#2656](https://github.com/ruby-grape/grape/pull/2656): Remove useless instance_variable_defined? checks - [@ericproulx](https://github.com/ericproulx).
12
+ * [#2619](https://github.com/ruby-grape/grape/pull/2619): Remove TOC from README.md and danger-toc check - [@alexanderadam](https://github.com/alexanderadam).
13
+ * [#2663](https://github.com/ruby-grape/grape/pull/2663): Refactor `ParamsScope` and `Parameters` DSL to use named kwargs - [@ericproulx](https://github.com/ericproulx).
14
+ * [#2664](https://github.com/ruby-grape/grape/pull/2664): Drop `test-prof` dependency - [@ericproulx](https://github.com/ericproulx).
15
+ * [#2665](https://github.com/ruby-grape/grape/pull/2665): Pass `attrs` directly to `AttributesIterator` instead of `validator` - [@ericproulx](https://github.com/ericproulx).
16
+ * [#2657](https://github.com/ruby-grape/grape/pull/2657): Instantiate validators at definition time - [@ericproulx](https://github.com/ericproulx).
17
+ * [#2667](https://github.com/ruby-grape/grape/pull/2667): Skip instrumentation in run_validators when no validators present - [@ericproulx](https://github.com/ericproulx).
18
+ * [#2670](https://github.com/ruby-grape/grape/pull/2670): Added support for Rack 3.2.6 and better handling to rack exceptions - [@ericproulx](https://github.com/ericproulx).
19
+ * [#2671](https://github.com/ruby-grape/grape/pull/2671): Use ruby 3.1 shorthand kwargs syntax - [@ericproulx](https://github.com/ericproulx).
20
+ * [#2672](https://github.com/ruby-grape/grape/pull/2672): Minor ruby optimizations - [@ericproulx](https://github.com/ericproulx).
21
+ * [#2675](https://github.com/ruby-grape/grape/pull/2675): Add `AGENTS.md` to please our future A.I. overlords - [@dblock](https://github.com/dblock).
22
+
23
+ #### Fixes
24
+
25
+ * [#2670](https://github.com/ruby-grape/grape/pull/2670): Fix `UnknownAuthStrategy` raised when custom auth strategy class inherits from `Grape::Middleware::Auth::Base` - [@dblock](https://github.com/dblock).
26
+ * [#2655](https://github.com/ruby-grape/grape/pull/2655): Fix `before_each` method to handle `nil` parameter correctly - [@ericproulx](https://github.com/ericproulx).
27
+ * [#2660](https://github.com/ruby-grape/grape/pull/2660): Fix thread safety: move mutable `ParamsScope` state (`index`, `params_meeting_dependency`) into a per-request `ParamScopeTracker` stored in `Fiber[]` - [@ericproulx](https://github.com/ericproulx).
28
+ * [#2666](https://github.com/ruby-grape/grape/pull/2666): Endpoint cleanup and minor optimizations - [@ericproulx](https://github.com/ericproulx).
29
+ * [#2676](https://github.com/ruby-grape/grape/pull/2676): Exclude ruby 3.2 for rails_edge - [@ericproulx](https://github.com/ericproulx).
30
+ * [#2677](https://github.com/ruby-grape/grape/pull/2677): Update actions/checkout to v6 - [@ericproulx](https://github.com/ericproulx).
31
+
32
+ ### 3.1.0 (2026-01-25)
33
+
34
+ #### Features
35
+
36
+ * [#2629](https://github.com/ruby-grape/grape/pull/2629): Refactor Router Architecture - [@ericproulx](https://github.com/ericproulx).
37
+ * [#2633](https://github.com/ruby-grape/grape/pull/2633): Refactor API::Instance and reorganize DSL modules - [@ericproulx](https://github.com/ericproulx).
38
+ * [#2636](https://github.com/ruby-grape/grape/pull/2636): Refactor router to simplify method signatures and reduce duplication - [@ericproulx](https://github.com/ericproulx).
39
+ * [#2640](https://github.com/ruby-grape/grape/pull/2640): Compute available_media_types once - [@ericproulx](https://github.com/ericproulx).
40
+ * [#2637](https://github.com/ruby-grape/grape/pull/2637): Refactor declared method - [@ericproulx](https://github.com/ericproulx).
41
+ * [#2639](https://github.com/ruby-grape/grape/pull/2639): Refactor mime_types_for - [@ericproulx](https://github.com/ericproulx).
42
+ * [#2638](https://github.com/ruby-grape/grape/pull/2638): Remove unnecessary path string duplication - [@ericproulx](https://github.com/ericproulx).
43
+ * [#2643](https://github.com/ruby-grape/grape/pull/2638): Remove `try` method in codebase - [@ericproulx](https://github.com/ericproulx).
44
+ * [#2646](https://github.com/ruby-grape/grape/pull/2646): Call `valid_encoding?` before scrub - [@ericproulx](https://github.com/ericproulx).
45
+ * [#2644](https://github.com/ruby-grape/grape/pull/2644): Clean useless/not valuable dependencies - [@ericproulx](https://github.com/ericproulx).
46
+ * [#2649](https://github.com/ruby-grape/grape/pull/2644): Drop support Ruby 3.0 and ActiveSupport 7.0 - [@ericproulx](https://github.com/ericproulx).
47
+ * [#2648](https://github.com/ruby-grape/grape/pull/2648): Remove deprecated ParamsBuilders extensions - [@ericproulx](https://github.com/ericproulx).
48
+ * [#2645](https://github.com/ruby-grape/grape/pull/2645): Endpoints are compiled when API is compiled - [@ericproulx](https://github.com/ericproulx).
49
+ * [#2647](https://github.com/ruby-grape/grape/pull/2647): Explicit kwargs for `namespace` and `route_param` - [@ericproulx](https://github.com/ericproulx).
50
+ * [#2651](https://github.com/ruby-grape/grape/pull/2651): Migrate Danger to use danger-pr-comment workflow - [@dblock](https://github.com/dblock).
51
+
52
+ #### Fixes
53
+
54
+ * [#2633](https://github.com/ruby-grape/grape/pull/2633): Fix cascade reading - [@ericproulx](https://github.com/ericproulx).
55
+ * [#2641](https://github.com/ruby-grape/grape/pull/2641): Restore support for `return` in endpoint blocks - [@ericproulx](https://github.com/ericproulx).
56
+ * [#2642](https://github.com/ruby-grape/grape/pull/2642): Fix array allocation in base_route.rb - [@ericproulx](https://github.com/ericproulx).
57
+ * Fix `before_each` method to handle `nil` parameter correctly - [@ericproulx](https://github.com/ericproulx).
58
+
59
+ ### 3.0.1 (2025-11-24)
60
+
61
+ #### Features
62
+
63
+ * [#2625](https://github.com/ruby-grape/grape/pull/2625): Update rubocop to 1.81.7 and fix style offenses - [@ericproulx](https://github.com/ericproulx).
64
+ * [#2626](https://github.com/ruby-grape/grape/pull/2626): Add rails 8.1 to CI test matrix - [@ericproulx](https://github.com/ericproulx).
65
+
66
+ #### Fixes
67
+
68
+ * [#2628](https://github.com/ruby-grape/grape/pull/2628): Fix helpers inheritance - [@giorni](https://github.com/giorni).
69
+
70
+ ### 3.0.0 (2025-11-15)
71
+
72
+ #### Features
73
+
74
+ * [#2572](https://github.com/ruby-grape/grape/pull/2572): Drop support ruby 2.7 and active_support 6.1 - [@ericproulx](https://github.com/ericproulx).
75
+ * [#2573](https://github.com/ruby-grape/grape/pull/2573): Clean up deprecated code - [@ericproulx](https://github.com/ericproulx).
76
+ * [#2575](https://github.com/ruby-grape/grape/pull/2575): Refactor Api description class - [@ericproulx](https://github.com/ericproulx).
77
+ * [#2577](https://github.com/ruby-grape/grape/pull/2577): Deprecate `return` in endpoint execution - [@ericproulx](https://github.com/ericproulx).
78
+ * [#2580](https://github.com/ruby-grape/grape/pull/2580): Refactor endpoint helpers and error middleware integration - [@ericproulx](https://github.com/ericproulx).
79
+ * [#2581](https://github.com/ruby-grape/grape/pull/2581): Delegate `to_s` in Grape::API::Instance - [@ericproulx](https://github.com/ericproulx).
80
+ * [#2582](https://github.com/ruby-grape/grape/pull/2582): Fix leaky slash when normalizing - [@ericproulx](https://github.com/ericproulx).
81
+ * [#2583](https://github.com/ruby-grape/grape/pull/2583): Optimize api parameter documentation and memory usage - [@ericproulx](https://github.com/ericproulx).
82
+ * [#2589](https://github.com/ruby-grape/grape/pull/2589): Replace `send` by `__send__` in codebase - [@ericproulx](https://github.com/ericproulx).
83
+ * [#2598](https://github.com/ruby-grape/grape/pull/2598): Refactor settings DSL to use explicit methods instead of dynamic generation - [@ericproulx](https://github.com/ericproulx).
84
+ * [#2599](https://github.com/ruby-grape/grape/pull/2599): Simplify settings DSL get_or_set method and optimize logger implementation - [@ericproulx](https://github.com/ericproulx).
85
+ * [#2600](https://github.com/ruby-grape/grape/pull/2600): Refactor versioner middleware: simplify base class and improve consistency - [@ericproulx](https://github.com/ericproulx).
86
+ * [#2601](https://github.com/ruby-grape/grape/pull/2601): Refactor route_setting internal usage to use inheritable_setting.route for improved consistency and performance - [@ericproulx](https://github.com/ericproulx).
87
+ * [#2602](https://github.com/ruby-grape/grape/pull/2602): Remove `namespace_reverse_stackable` from public DSL interface and use direct inheritable_setting access - [@ericproulx](https://github.com/ericproulx).
88
+ * [#2603](https://github.com/ruby-grape/grape/pull/2603): Remove `namespace_stackable_with_hash` from public interface and move to internal InheritableSetting - [@ericproulx](https://github.com/ericproulx).
89
+ * [#2604](https://github.com/ruby-grape/grape/pull/2604): Enable branch coverage - [@ericproulx](https://github.com/ericproulx).
90
+ * [#2605](https://github.com/ruby-grape/grape/pull/2605): Add Rack 3.2 support with new gemfile and CI integration - [@ericproulx](https://github.com/ericproulx).
91
+ * [#2607](https://github.com/ruby-grape/grape/pull/2607): Remove namespace_stackable and namespace_inheritable from public API - [@ericproulx](https://github.com/ericproulx).
92
+ * [#2615](https://github.com/ruby-grape/grape/pull/2615): Remove manual toc and tod danger check - [@alexanderadam](https://github.com/alexanderadam).
93
+ * [#2612](https://github.com/ruby-grape/grape/pull/2612): Avoid multiple mount pollution - [@alexanderadam](https://github.com/alexanderadam).
94
+ * [#2617](https://github.com/ruby-grape/grape/pull/2617): Migrate from `ActiveSupport::Configurable` to `Dry::Configurable` - [@ericproulx](https://github.com/ericproulx).
95
+ * [#2618](https://github.com/ruby-grape/grape/pull/2618): Modernize argument delegation for Ruby 3+ compatibility - [@ericproulx](https://github.com/ericproulx).
96
+ * [#2623](https://github.com/ruby-grape/grape/pull/2623): Refactor coercer caching to use `Grape::Util::Cache` - [@ericproulx](https://github.com/ericproulx).
97
+
98
+ #### Fixes
99
+
100
+ * [#2586](https://github.com/ruby-grape/grape/pull/2586): Limit helpers DSL public scope - [@ericproulx](https://github.com/ericproulx).
101
+ * [#2588](https://github.com/ruby-grape/grape/pull/2588): Fix defaut format regression on */* - [@ericproulx](https://github.com/ericproulx).
102
+ * [#2593](https://github.com/ruby-grape/grape/pull/2593): Fix warning message when overriding global registry key - [@ericproulx](https://github.com/ericproulx).
103
+ * [#2594](https://github.com/ruby-grape/grape/pull/2594): Fix routes memoization - [@ericproulx](https://github.com/ericproulx).
104
+ * [#2595](https://github.com/ruby-grape/grape/pull/2595): Keep `within_namespace` as part of our internal api - [@ericproulx](https://github.com/ericproulx).
105
+ * [#2596](https://github.com/ruby-grape/grape/pull/2596): Remove `namespace_reverse_stackable_with_hash` from public scope - [@ericproulx](https://github.com/ericproulx).
106
+ * [#2621](https://github.com/ruby-grape/grape/pull/2621): Update upgrading notes regarding `return` usage and simplify endpoint execution - [@ericproulx](https://github.com/ericproulx).
107
+ * [#2622](https://github.com/ruby-grape/grape/pull/2622): Use `require_relative` instead of `$LOAD_PATH` in gemspec - [@ericproulx](https://github.com/ericproulx).
108
+
1
109
  ### 2.4.0 (2025-06-18)
2
110
 
3
111
  #### Features
@@ -1165,3 +1273,4 @@
1165
1273
  ### 0.1.0 (2010/11/13)
1166
1274
 
1167
1275
  * Initial public release - [@mbleigh](https://github.com/mbleigh).
1276
+
data/CONTRIBUTING.md CHANGED
@@ -48,8 +48,8 @@ Here are some examples:
48
48
  - running rspec on a specific file `docker-compose run --rm --build grape rspec spec/:file_path`
49
49
  - running task `docker-compose run --rm --build grape rake <task_name>`
50
50
  - running rubocop `docker-compose run --rm --build grape rubocop`
51
- - running all specs on a specific ruby version (e.g 2.7.7) `RUBY_VERSION=2.7.7 docker-compose run --rm --build grape rspec`
52
- - running specs on a specific gemfile (e.g rails_7_0.gemfile) `docker-compose run -e GEMFILE=rails_7_0 --rm --build grape rspec`
51
+ - running all specs on a specific ruby version (e.g 3.4) `RUBY_VERSION=3.4 docker-compose run --rm --build grape rspec`
52
+ - running specs on a specific gemfile (e.g rails_8_1.gemfile) `docker-compose run -e GEMFILE=rails_8_1 --rm --build grape rspec`
53
53
 
54
54
  #### Bundle Install and Test
55
55
 
@@ -60,14 +60,6 @@ bundle install
60
60
  bundle exec rake
61
61
  ```
62
62
 
63
- Run tests against all supported versions of Rails.
64
-
65
- ```
66
- gem install appraisal
67
- appraisal install
68
- appraisal rake spec
69
- ```
70
-
71
63
  #### Write Tests
72
64
 
73
65
  Try to write a test that reproduces the problem you're trying to fix or describes a feature that you want to build. Add to [spec/grape](spec/grape).
data/README.md CHANGED
@@ -4,160 +4,13 @@
4
4
  [![test](https://github.com/ruby-grape/grape/actions/workflows/test.yml/badge.svg)](https://github.com/ruby-grape/grape/actions/workflows/test.yml)
5
5
  [![Coverage Status](https://coveralls.io/repos/github/ruby-grape/grape/badge.svg?branch=master)](https://coveralls.io/github/ruby-grape/grape?branch=master)
6
6
 
7
- ## Table of Contents
8
-
9
- - [What is Grape?](#what-is-grape)
10
- - [Stable Release](#stable-release)
11
- - [Project Resources](#project-resources)
12
- - [Grape for Enterprise](#grape-for-enterprise)
13
- - [Installation](#installation)
14
- - [Basic Usage](#basic-usage)
15
- - [Rails 7.1](#rails-71)
16
- - [Mounting](#mounting)
17
- - [All](#all)
18
- - [Rack](#rack)
19
- - [Alongside Sinatra (or other frameworks)](#alongside-sinatra-or-other-frameworks)
20
- - [Rails](#rails)
21
- - [Zeitwerk](#zeitwerk)
22
- - [Modules](#modules)
23
- - [Remounting](#remounting)
24
- - [Mount Configuration](#mount-configuration)
25
- - [Versioning](#versioning)
26
- - [Strategies](#strategies)
27
- - [Path](#path)
28
- - [Header](#header)
29
- - [Accept-Version Header](#accept-version-header)
30
- - [Param](#param)
31
- - [Linting](#linting)
32
- - [Bug in Rack::ETag under Rack 3.X](#bug-in-racketag-under-rack-3x)
33
- - [Describing Methods](#describing-methods)
34
- - [Configuration](#configuration)
35
- - [Parameters](#parameters)
36
- - [Params Class](#params-class)
37
- - [Declared](#declared)
38
- - [Include Parent Namespaces](#include-parent-namespaces)
39
- - [Include Missing](#include-missing)
40
- - [Evaluate Given](#evaluate-given)
41
- - [Parameter Precedence](#parameter-precedence)
42
- - [Parameter Validation and Coercion](#parameter-validation-and-coercion)
43
- - [Supported Parameter Types](#supported-parameter-types)
44
- - [Integer/Fixnum and Coercions](#integerfixnum-and-coercions)
45
- - [Custom Types and Coercions](#custom-types-and-coercions)
46
- - [Multipart File Parameters](#multipart-file-parameters)
47
- - [First-Class JSON Types](#first-class-json-types)
48
- - [Multiple Allowed Types](#multiple-allowed-types)
49
- - [Validation of Nested Parameters](#validation-of-nested-parameters)
50
- - [Dependent Parameters](#dependent-parameters)
51
- - [Group Options](#group-options)
52
- - [Renaming](#renaming)
53
- - [Built-in Validators](#built-in-validators)
54
- - [allow_blank](#allow_blank)
55
- - [values](#values)
56
- - [except_values](#except_values)
57
- - [same_as](#same_as)
58
- - [length](#length)
59
- - [regexp](#regexp)
60
- - [mutually_exclusive](#mutually_exclusive)
61
- - [exactly_one_of](#exactly_one_of)
62
- - [at_least_one_of](#at_least_one_of)
63
- - [all_or_none_of](#all_or_none_of)
64
- - [Nested mutually_exclusive, exactly_one_of, at_least_one_of, all_or_none_of](#nested-mutually_exclusive-exactly_one_of-at_least_one_of-all_or_none_of)
65
- - [Namespace Validation and Coercion](#namespace-validation-and-coercion)
66
- - [Custom Validators](#custom-validators)
67
- - [Validation Errors](#validation-errors)
68
- - [I18n](#i18n)
69
- - [Custom Validation messages](#custom-validation-messages)
70
- - [presence, allow_blank, values, regexp](#presence-allow_blank-values-regexp)
71
- - [same_as](#same_as-1)
72
- - [length](#length-1)
73
- - [all_or_none_of](#all_or_none_of-1)
74
- - [mutually_exclusive](#mutually_exclusive-1)
75
- - [exactly_one_of](#exactly_one_of-1)
76
- - [at_least_one_of](#at_least_one_of-1)
77
- - [Coerce](#coerce)
78
- - [With Lambdas](#with-lambdas)
79
- - [Pass symbols for i18n translations](#pass-symbols-for-i18n-translations)
80
- - [Overriding Attribute Names](#overriding-attribute-names)
81
- - [With Default](#with-default)
82
- - [Using dry-validation or dry-schema](#using-dry-validation-or-dry-schema)
83
- - [Headers](#headers)
84
- - [Request](#request)
85
- - [Header Case Handling](#header-case-handling)
86
- - [Response](#response)
87
- - [Routes](#routes)
88
- - [Helpers](#helpers)
89
- - [Path Helpers](#path-helpers)
90
- - [Parameter Documentation](#parameter-documentation)
91
- - [Cookies](#cookies)
92
- - [HTTP Status Code](#http-status-code)
93
- - [Redirecting](#redirecting)
94
- - [Recognizing Path](#recognizing-path)
95
- - [Allowed Methods](#allowed-methods)
96
- - [Raising Exceptions](#raising-exceptions)
97
- - [Default Error HTTP Status Code](#default-error-http-status-code)
98
- - [Handling 404](#handling-404)
99
- - [Exception Handling](#exception-handling)
100
- - [Rescuing exceptions inside namespaces](#rescuing-exceptions-inside-namespaces)
101
- - [Unrescuable Exceptions](#unrescuable-exceptions)
102
- - [Exceptions that should be rescued explicitly](#exceptions-that-should-be-rescued-explicitly)
103
- - [Logging](#logging)
104
- - [API Formats](#api-formats)
105
- - [JSONP](#jsonp)
106
- - [CORS](#cors)
107
- - [Content-type](#content-type)
108
- - [API Data Formats](#api-data-formats)
109
- - [JSON and XML Processors](#json-and-xml-processors)
110
- - [RESTful Model Representations](#restful-model-representations)
111
- - [Grape Entities](#grape-entities)
112
- - [Hypermedia and Roar](#hypermedia-and-roar)
113
- - [Rabl](#rabl)
114
- - [Active Model Serializers](#active-model-serializers)
115
- - [Sending Raw or No Data](#sending-raw-or-no-data)
116
- - [Authentication](#authentication)
117
- - [Basic Auth](#basic-auth)
118
- - [Register custom middleware for authentication](#register-custom-middleware-for-authentication)
119
- - [Describing and Inspecting an API](#describing-and-inspecting-an-api)
120
- - [Current Route and Endpoint](#current-route-and-endpoint)
121
- - [Before, After and Finally](#before-after-and-finally)
122
- - [Anchoring](#anchoring)
123
- - [Instance Variables](#instance-variables)
124
- - [Using Custom Middleware](#using-custom-middleware)
125
- - [Grape Middleware](#grape-middleware)
126
- - [Rails Middleware](#rails-middleware)
127
- - [Remote IP](#remote-ip)
128
- - [Writing Tests](#writing-tests)
129
- - [Writing Tests with Rack](#writing-tests-with-rack)
130
- - [RSpec](#rspec)
131
- - [Airborne](#airborne)
132
- - [MiniTest](#minitest)
133
- - [Writing Tests with Rails](#writing-tests-with-rails)
134
- - [RSpec](#rspec-1)
135
- - [MiniTest](#minitest-1)
136
- - [Stubbing Helpers](#stubbing-helpers)
137
- - [Reloading API Changes in Development](#reloading-api-changes-in-development)
138
- - [Reloading in Rack Applications](#reloading-in-rack-applications)
139
- - [Reloading in Rails Applications](#reloading-in-rails-applications)
140
- - [Performance Monitoring](#performance-monitoring)
141
- - [Active Support Instrumentation](#active-support-instrumentation)
142
- - [endpoint_run.grape](#endpoint_rungrape)
143
- - [endpoint_render.grape](#endpoint_rendergrape)
144
- - [endpoint_run_filters.grape](#endpoint_run_filtersgrape)
145
- - [endpoint_run_validators.grape](#endpoint_run_validatorsgrape)
146
- - [format_response.grape](#format_responsegrape)
147
- - [Monitoring Products](#monitoring-products)
148
- - [Contributing to Grape](#contributing-to-grape)
149
- - [Security](#security)
150
- - [License](#license)
151
- - [Copyright](#copyright)
152
-
153
7
  ## What is Grape?
154
8
 
155
9
  Grape is a REST-like API framework for Ruby. It's designed to run on Rack or complement existing web application frameworks such as Rails and Sinatra by providing a simple DSL to easily develop RESTful APIs. It has built-in support for common conventions, including multiple formats, subdomain/prefix restriction, content negotiation, versioning and much more.
156
10
 
157
11
  ## Stable Release
158
12
 
159
- You're reading the documentation for the stable release of Grape, 2.4.0.
160
- Please read [UPGRADING](https://github.com/ruby-grape/grape/blob/v2.4.0/UPGRADING.md) when upgrading from a previous version.
13
+ You're reading the documentation for the stable release of Grape, 3.2.1.
161
14
 
162
15
  ## Project Resources
163
16
 
@@ -174,7 +27,7 @@ The maintainers of Grape are working with Tidelift to deliver commercial support
174
27
 
175
28
  ## Installation
176
29
 
177
- Ruby 2.7 or newer is required.
30
+ Ruby 3.2 or newer is required.
178
31
 
179
32
  Grape is available as a gem, to install it run:
180
33
 
@@ -1920,9 +1773,9 @@ end
1920
1773
  ```ruby
1921
1774
  class AlphaNumeric < Grape::Validations::Validators::Base
1922
1775
  def validate_param!(attr_name, params)
1923
- unless params[attr_name] =~ /\A[[:alnum:]]+\z/
1924
- raise Grape::Exceptions::Validation.new params: [@scope.full_name(attr_name)], message: 'must consist of alpha-numeric characters'
1925
- end
1776
+ return if params[attr_name].match?(/\A[[:alnum:]]+\z/)
1777
+
1778
+ validation_error!(attr_name, 'must consist of alpha-numeric characters')
1926
1779
  end
1927
1780
  end
1928
1781
  ```
@@ -1938,9 +1791,9 @@ You can also create custom classes that take parameters.
1938
1791
  ```ruby
1939
1792
  class Length < Grape::Validations::Validators::Base
1940
1793
  def validate_param!(attr_name, params)
1941
- unless params[attr_name].length <= @option
1942
- raise Grape::Exceptions::Validation.new params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long"
1943
- end
1794
+ return if params[attr_name].length <= @options
1795
+
1796
+ validation_error!(attr_name, "must be at the most #{@options} characters long")
1944
1797
  end
1945
1798
  end
1946
1799
  ```
@@ -1962,10 +1815,10 @@ class Admin < Grape::Validations::Validators::Base
1962
1815
  # @attrs being [:admin_field] and once with @attrs being [:admin_false_field]
1963
1816
  return unless request.params.key?(@attrs.first)
1964
1817
  # check if admin flag is set to true
1965
- return unless @option
1818
+ return unless @options
1966
1819
  # check if user is admin or not
1967
1820
  # as an example get a token from request and check if it's admin or not
1968
- raise Grape::Exceptions::Validation.new params: @attrs, message: 'Can not set admin-only field.' unless request.headers['X-Access-Token'] == 'admin'
1821
+ validation_error!(@attrs, 'Can not set admin-only field.') unless request.headers['X-Access-Token'] == 'admin'
1969
1822
  end
1970
1823
  end
1971
1824
  ```
@@ -1980,7 +1833,50 @@ params do
1980
1833
  end
1981
1834
  ```
1982
1835
 
1983
- Every validation will have its own instance of the validator, which means that the validator can have a state.
1836
+ Each validator is instantiated once at route definition time and frozen. Any setup (option parsing, message building) should happen in `initialize`, not in `validate_param!` or `validate`.
1837
+
1838
+ #### Available helpers
1839
+
1840
+ The following protected/private helpers are available in any `Grape::Validations::Validators::Base` subclass:
1841
+
1842
+ | Helper | Description |
1843
+ |---|---|
1844
+ | `default_message_key(key)` | Class-level macro. Declares the default I18n key for `validation_error!`. A per-option `:message` override still takes precedence. |
1845
+ | `validation_error!(attr_name_or_params, message = @exception_message)` | Raises `Grape::Exceptions::Validation`. Accepts a single attribute name or a pre-computed array of full param names. |
1846
+ | `@options` | The validator option value, deep-frozen at initialization. |
1847
+ | `@attrs` | Frozen array of attribute names this validator applies to. |
1848
+ | `@scope` | The `ParamsScope` — use `@scope.full_name(attr_name)` for the fully-qualified param name. |
1849
+ | `option_value` | Returns `@options[:value]` if present, otherwise `@options`. |
1850
+ | `options_key?(key)` | Returns true if `@options` is a hash with a non-nil `key`. |
1851
+ | `hash_like?(obj)` | Returns true if `obj` responds to `key?`. |
1852
+ | `scrub(value)` | Returns `value` with invalid byte sequences scrubbed. |
1853
+ | `translate(key, **opts)` | I18n lookup with `:en` fallback and `grape.errors.messages` scope. Called at request time to respect per-request locale. |
1854
+
1855
+ Use `default_message_key` for a fixed I18n key. The message is resolved once at route definition time via `message`, so a per-option `:message` override still wins:
1856
+
1857
+ ```ruby
1858
+ class SpecialValidator < Grape::Validations::Validators::Base
1859
+ default_message_key :special
1860
+
1861
+ def validate_param!(attr_name, params)
1862
+ return if valid?(params[attr_name])
1863
+
1864
+ validation_error!(attr_name)
1865
+ end
1866
+ end
1867
+ ```
1868
+
1869
+ For interpolated messages that must respect per-request locale, call `translate` directly inside `validate_param!`:
1870
+
1871
+ ```ruby
1872
+ class SpecialValidator < Grape::Validations::Validators::Base
1873
+ def validate_param!(attr_name, params)
1874
+ return if valid?(params[attr_name])
1875
+
1876
+ validation_error!(attr_name, translate(:special, min: 2, max: 10))
1877
+ end
1878
+ end
1879
+ ```
1984
1880
 
1985
1881
  ### Validation Errors
1986
1882
 
@@ -2042,6 +1938,28 @@ Grape supports I18n for parameter-related error messages, but will fallback to E
2042
1938
 
2043
1939
  In case your app enforces available locales only and :en is not included in your available locales, Grape cannot fall back to English and will return the translation key for the error message. To avoid this behaviour, either provide a translation for your default locale or add :en to your available locales.
2044
1940
 
1941
+ Custom validators that inherit from `Grape::Validations::Validators::Base` have access to a `translate` helper (see `Grape::Util::Translation`) and should use it instead of calling `I18n` directly. It applies the same `:en` fallback as built-in validators, defaults `scope` to `'grape.errors.messages'`, and handles interpolation without needing `format`:
1942
+
1943
+ ```ruby
1944
+ # Good — scope defaults to 'grape.errors.messages', interpolation forwarded automatically
1945
+ translate(:special, min: 2, max: 10)
1946
+
1947
+ # Bad — format is unnecessary and risks conflicting with I18n reserved keys
1948
+ format I18n.t(:special, scope: 'grape.errors.messages'), min: 2, max: 10
1949
+ ```
1950
+
1951
+ Example custom validator using an interpolated i18n message:
1952
+
1953
+ ```ruby
1954
+ class SpecialValidator < Grape::Validations::Validators::Base
1955
+ def validate_param!(attr_name, params)
1956
+ return if valid?(params[attr_name])
1957
+
1958
+ validation_error!(attr_name, translate(:special, min: 2, max: 10))
1959
+ end
1960
+ end
1961
+ ```
1962
+
2045
1963
  ### Custom Validation messages
2046
1964
 
2047
1965
  Grape supports custom validation messages for parameter-related and coerce-related error messages.
@@ -4077,6 +3995,25 @@ Use [grape-reload](https://github.com/AlexYankee/grape-reload).
4077
3995
 
4078
3996
  ### Reloading in Rails Applications
4079
3997
 
3998
+ #### Rails 7+ (Zeitwerk)
3999
+
4000
+ Rails 7+ uses [Zeitwerk](https://github.com/fxn/zeitwerk) as the default autoloader, which automatically handles reloading of code in development mode without any additional configuration.
4001
+
4002
+ If your API files are in `app/api`, Zeitwerk will automatically autoload and reload them. No additional configuration is needed.
4003
+
4004
+ If you encounter issues with reloading, ensure that:
4005
+
4006
+ 1. Your API files follow Zeitwerk naming conventions (file names should match class names).
4007
+ 2. The `config.enable_reloading` is set to `true` in `config/environments/development.rb` (this is the default).
4008
+
4009
+ For troubleshooting autoloading issues, have a look at the [Rails documentation](https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#troubleshooting).
4010
+
4011
+ See the [Rails Autoloading and Reloading Constants guide](https://guides.rubyonrails.org/autoloading_and_reloading_constants.html) for more information.
4012
+
4013
+ #### Rails 6 and Earlier
4014
+
4015
+ For Rails versions before 7, you need to configure reloading manually.
4016
+
4080
4017
  Add API paths to `config/application.rb`.
4081
4018
 
4082
4019
  ```ruby
@@ -4095,28 +4032,12 @@ if Rails.env.development?
4095
4032
  api_reloader = ActiveSupport::FileUpdateChecker.new(api_files) do
4096
4033
  Rails.application.reload_routes!
4097
4034
  end
4098
- ActionDispatch::Callbacks.to_prepare do
4035
+ ActiveSupport::Reloader.to_prepare do
4099
4036
  api_reloader.execute_if_updated
4100
4037
  end
4101
4038
  end
4102
4039
  ```
4103
4040
 
4104
- For Rails >= 5.1.4, change this:
4105
-
4106
- ```ruby
4107
- ActionDispatch::Callbacks.to_prepare do
4108
- api_reloader.execute_if_updated
4109
- end
4110
- ```
4111
-
4112
- to this:
4113
-
4114
- ```ruby
4115
- ActiveSupport::Reloader.to_prepare do
4116
- api_reloader.execute_if_updated
4117
- end
4118
- ```
4119
-
4120
4041
  See [StackOverflow #3282655](http://stackoverflow.com/questions/3282655/ruby-on-rails-3-reload-lib-directory-for-each-request/4368838#4368838) for more information.
4121
4042
 
4122
4043
  ## Performance Monitoring
@@ -4125,27 +4046,30 @@ See [StackOverflow #3282655](http://stackoverflow.com/questions/3282655/ruby-on-
4125
4046
 
4126
4047
  Grape has built-in support for [ActiveSupport::Notifications](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html) which provides simple hook points to instrument key parts of your application.
4127
4048
 
4128
- The following are currently supported:
4129
4049
 
4130
- #### endpoint_run.grape
4050
+ #### Hook Points
4051
+
4052
+ The following hook points are currently supported:
4053
+
4054
+ ##### endpoint_run.grape
4131
4055
 
4132
4056
  The main execution of an endpoint, includes filters and rendering.
4133
4057
 
4134
4058
  * *endpoint* - The endpoint instance
4135
4059
 
4136
- #### endpoint_render.grape
4060
+ ##### endpoint_render.grape
4137
4061
 
4138
4062
  The execution of the main content block of the endpoint.
4139
4063
 
4140
4064
  * *endpoint* - The endpoint instance
4141
4065
 
4142
- #### endpoint_run_filters.grape
4066
+ ##### endpoint_run_filters.grape
4143
4067
 
4144
4068
  * *endpoint* - The endpoint instance
4145
4069
  * *filters* - The filters being executed
4146
4070
  * *type* - The type of filters (before, before_validation, after_validation, after)
4147
4071
 
4148
- #### endpoint_run_validators.grape
4072
+ ##### endpoint_run_validators.grape
4149
4073
 
4150
4074
  The execution of validators.
4151
4075
 
@@ -4153,7 +4077,7 @@ The execution of validators.
4153
4077
  * *validators* - The validators being executed
4154
4078
  * *request* - The request being validated
4155
4079
 
4156
- #### format_response.grape
4080
+ ##### format_response.grape
4157
4081
 
4158
4082
  Serialization or template rendering.
4159
4083
 
@@ -4162,12 +4086,44 @@ Serialization or template rendering.
4162
4086
 
4163
4087
  See the [ActiveSupport::Notifications documentation](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html) for information on how to subscribe to these events.
4164
4088
 
4089
+ #### Subscribe to Hooks
4090
+
4091
+ Once subscribed to the instrumentation, you can intercept the events reported above.
4092
+
4093
+ ```ruby
4094
+ ActiveSupport::Notifications.subscribe(/<api_path>/) do |name, start, finish, id, payload|
4095
+ # your code to intercept the notification
4096
+ end
4097
+ ```
4098
+
4099
+ The request data, the API’s internal data, and the response can be retrieved from the payload.
4100
+
4101
+ You can use `payload.fetch(:endpoint)` or directly `payload[:endpoint]`.
4102
+
4103
+ The `:endpoint` contains the data currently being processed, and access to attributes such as `body`, `request`, `params`, `headers`, `cookies` and `response_cookies`
4104
+
4105
+ For example, `payload[:endpoint].body` provides the current state of the response.
4106
+
4107
+ ```ruby
4108
+ ActiveSupport::Notifications.subscribe(/v1/) do |name, start, finish, id, payload|
4109
+ hook_record = {
4110
+ hook: name
4111
+ status: payload[:env]&.dig("api.endpoint")&.status
4112
+ format: payload[:env]&.dig("api.format")
4113
+ body: payload[:endpoint]&.body
4114
+ duration: (finish - start) * 1000
4115
+ }
4116
+ # your code to save the notification
4117
+ end
4118
+ ```
4119
+
4165
4120
  ### Monitoring Products
4166
4121
 
4167
4122
  Grape integrates with following third-party tools:
4168
4123
 
4169
4124
  * **New Relic** - [built-in support](https://docs.newrelic.com/docs/agents/ruby-agent/frameworks/grape-instrumentation) from v3.10.0 of the official [newrelic_rpm](https://github.com/newrelic/rpm) gem, also [newrelic-grape](https://github.com/xinminlabs/newrelic-grape) gem
4170
4125
  * **Librato Metrics** - [grape-librato](https://github.com/seanmoon/grape-librato) gem
4126
+ * **Rails Performance** - [rails_performance](https://github.com/igorkasyanchuk/rails_performance) gem
4171
4127
  * **[Skylight](https://www.skylight.io/)** - [skylight](https://github.com/skylightio/skylight-ruby) gem, [documentation](https://docs.skylight.io/grape/)
4172
4128
  * **[AppSignal](https://www.appsignal.com)** - [appsignal-ruby](https://github.com/appsignal/appsignal-ruby) gem, [documentation](http://docs.appsignal.com/getting-started/supported-frameworks.html#grape)
4173
4129
  * **[ElasticAPM](https://www.elastic.co/products/apm)** - [elastic-apm](https://github.com/elastic/apm-agent-ruby) gem, [documentation](https://www.elastic.co/guide/en/apm/agent/ruby/3.x/getting-started-rack.html#getting-started-grape)