grape 1.3.1 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -1
  3. data/LICENSE +1 -1
  4. data/README.md +104 -21
  5. data/UPGRADING.md +265 -39
  6. data/lib/grape.rb +2 -2
  7. data/lib/grape/api.rb +2 -2
  8. data/lib/grape/api/instance.rb +29 -28
  9. data/lib/grape/dsl/helpers.rb +1 -0
  10. data/lib/grape/dsl/inside_route.rb +69 -36
  11. data/lib/grape/dsl/parameters.rb +7 -3
  12. data/lib/grape/dsl/routing.rb +2 -4
  13. data/lib/grape/dsl/validations.rb +18 -1
  14. data/lib/grape/eager_load.rb +1 -1
  15. data/lib/grape/endpoint.rb +8 -6
  16. data/lib/grape/http/headers.rb +1 -0
  17. data/lib/grape/middleware/base.rb +2 -1
  18. data/lib/grape/middleware/error.rb +10 -12
  19. data/lib/grape/middleware/formatter.rb +3 -3
  20. data/lib/grape/middleware/stack.rb +21 -8
  21. data/lib/grape/middleware/versioner/header.rb +1 -1
  22. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  23. data/lib/grape/path.rb +2 -2
  24. data/lib/grape/request.rb +1 -1
  25. data/lib/grape/router.rb +30 -43
  26. data/lib/grape/router/attribute_translator.rb +26 -5
  27. data/lib/grape/router/route.rb +3 -22
  28. data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
  29. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
  30. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
  31. data/lib/grape/util/base_inheritable.rb +11 -8
  32. data/lib/grape/util/lazy_value.rb +1 -0
  33. data/lib/grape/util/reverse_stackable_values.rb +3 -1
  34. data/lib/grape/util/stackable_values.rb +3 -1
  35. data/lib/grape/validations/attributes_iterator.rb +8 -0
  36. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  37. data/lib/grape/validations/params_scope.rb +8 -6
  38. data/lib/grape/validations/single_attribute_iterator.rb +1 -1
  39. data/lib/grape/validations/types.rb +6 -5
  40. data/lib/grape/validations/types/array_coercer.rb +14 -5
  41. data/lib/grape/validations/types/build_coercer.rb +5 -8
  42. data/lib/grape/validations/types/custom_type_coercer.rb +14 -2
  43. data/lib/grape/validations/types/dry_type_coercer.rb +36 -1
  44. data/lib/grape/validations/types/file.rb +15 -13
  45. data/lib/grape/validations/types/json.rb +40 -36
  46. data/lib/grape/validations/types/primitive_coercer.rb +11 -5
  47. data/lib/grape/validations/types/set_coercer.rb +6 -4
  48. data/lib/grape/validations/types/variant_collection_coercer.rb +1 -1
  49. data/lib/grape/validations/validator_factory.rb +1 -1
  50. data/lib/grape/validations/validators/as.rb +1 -1
  51. data/lib/grape/validations/validators/base.rb +4 -5
  52. data/lib/grape/validations/validators/coerce.rb +3 -10
  53. data/lib/grape/validations/validators/default.rb +3 -5
  54. data/lib/grape/validations/validators/except_values.rb +1 -1
  55. data/lib/grape/validations/validators/multiple_params_base.rb +2 -1
  56. data/lib/grape/validations/validators/regexp.rb +1 -1
  57. data/lib/grape/validations/validators/values.rb +1 -1
  58. data/lib/grape/version.rb +1 -1
  59. data/spec/grape/api/instance_spec.rb +50 -0
  60. data/spec/grape/api_spec.rb +75 -0
  61. data/spec/grape/dsl/inside_route_spec.rb +182 -33
  62. data/spec/grape/endpoint/declared_spec.rb +601 -0
  63. data/spec/grape/endpoint_spec.rb +0 -521
  64. data/spec/grape/entity_spec.rb +6 -0
  65. data/spec/grape/integration/rack_sendfile_spec.rb +12 -8
  66. data/spec/grape/middleware/auth/strategies_spec.rb +1 -1
  67. data/spec/grape/middleware/error_spec.rb +1 -1
  68. data/spec/grape/middleware/formatter_spec.rb +1 -1
  69. data/spec/grape/middleware/stack_spec.rb +3 -1
  70. data/spec/grape/path_spec.rb +4 -4
  71. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +13 -3
  72. data/spec/grape/validations/params_scope_spec.rb +26 -0
  73. data/spec/grape/validations/single_attribute_iterator_spec.rb +17 -6
  74. data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
  75. data/spec/grape/validations/types/primitive_coercer_spec.rb +65 -5
  76. data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
  77. data/spec/grape/validations/types_spec.rb +1 -1
  78. data/spec/grape/validations/validators/coerce_spec.rb +317 -29
  79. data/spec/grape/validations/validators/default_spec.rb +170 -0
  80. data/spec/grape/validations/validators/except_values_spec.rb +1 -0
  81. data/spec/grape/validations/validators/values_spec.rb +1 -1
  82. data/spec/grape/validations_spec.rb +290 -18
  83. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  84. data/spec/spec_helper.rb +0 -10
  85. data/spec/support/chunks.rb +14 -0
  86. data/spec/support/versioned_helpers.rb +3 -5
  87. metadata +18 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1711dd2fb0f0c86757c7e73d780907efa87e3da54e0a999a4b45c276b5eec92c
4
- data.tar.gz: f5ba49001d1816d92130f70fb1b63ae061d7d9250142605f706d75c207880ad9
3
+ metadata.gz: fc2b398e9ad95e7e4bb2641bbdaada929d992cd50fb551b56dbafe5f03a75589
4
+ data.tar.gz: 03765fbe9d5dafb28b531f2a454f06b2ac59d16ea28691036de797b8e64ced06
5
5
  SHA512:
6
- metadata.gz: 8b2dcf4d4903e3923dd10086a3371258404756cf294cd42c6fb64f3d2520fe7243c0accfe1b68f2e02fbaa85f29396c161d830cde4c5fdedd660b31e8d223a7f
7
- data.tar.gz: 88a4d5e9740495430cd28ed1e213d6aafd92895c1b7966bd6358dd6aeb5b2e1f16eac2e14834d63e7791a6d66e16475ef30cdef5e37d10bca0f38f1d1a22c1e4
6
+ metadata.gz: a078c1c951ff6e5dfee34c78ab04e1f2866be316af23de469db12301ec3c86eb53bcdc9c8ac478aabe02bd3dc34f4772166e49bdf85ef731a051a8d0de73441f
7
+ data.tar.gz: 7146c097cfced8308f1efb314fb3ace44f30013af8a58a01e9a41a9aca497bd5591c060cabdcc542f25d5660b842548916282541fe869f627538ef51bb083c66
@@ -1,3 +1,83 @@
1
+ ### 1.5.1 (2020/11/15)
2
+
3
+ #### Fixes
4
+
5
+ * Your contribution here.
6
+ * [#2129](https://github.com/ruby-grape/grape/pull/2129): Fix validation error when Required Array nested inside an optional array, for Multiparam validators - [@dwhenry](https://github.com/dwhenry).
7
+ * [#2128](https://github.com/ruby-grape/grape/pull/2128): Fix validation error when Required Array nested inside an optional array - [@dwhenry](https://github.com/dwhenry).
8
+ * [#2127](https://github.com/ruby-grape/grape/pull/2127): Fix a performance issue with dependent params - [@dnesteryuk](https://github.com/dnesteryuk).
9
+ * [#2126](https://github.com/ruby-grape/grape/pull/2126): Fix warnings about redefined attribute accessors in `AttributeTranslator` - [@samsonjs](https://github.com/samsonjs).
10
+ * [#2121](https://github.com/ruby-grape/grape/pull/2121): Fix 2.7 deprecation warning in validator_factory - [@Legogris](https://github.com/Legogris).
11
+ * [#2115](https://github.com/ruby-grape/grape/pull/2115): Fix declared_params regression with multiple allowed types - [@stanhu](https://github.com/stanhu).
12
+ * [#2123](https://github.com/ruby-grape/grape/pull/2123): Fix 2.7 deprecation warning in middleware/stack - [@Legogris](https://github.com/Legogris).
13
+
14
+ ### 1.5.0 (2020/10/05)
15
+
16
+ #### Fixes
17
+
18
+ * [#2104](https://github.com/ruby-grape/grape/pull/2104): Fix Ruby 2.7 keyword deprecation warning - [@stanhu](https://github.com/stanhu).
19
+ * [#2103](https://github.com/ruby-grape/grape/pull/2103): Ensure complete declared params structure is present - [@tlconnor](https://github.com/tlconnor).
20
+ * [#2099](https://github.com/ruby-grape/grape/pull/2099): Added truffleruby to Travis-CI - [@gogainda](https://github.com/gogainda).
21
+ * [#2089](https://github.com/ruby-grape/grape/pull/2089): Specify order of mounting Grape with Rack::Cascade in README - [@jonmchan](https://github.com/jonmchan).
22
+ * [#2083](https://github.com/ruby-grape/grape/pull/2083): Set `Cache-Control` header only for streamed responses - [@stanhu](https://github.com/stanhu).
23
+ * [#2092](https://github.com/ruby-grape/grape/pull/2092): Correct an example params in Include Missing doc - [@huyvohcmc](https://github.com/huyvohcmc).
24
+ * [#2091](https://github.com/ruby-grape/grape/pull/2091): Fix ruby 2.7 keyword deprecations - [@dim](https://github.com/dim).
25
+ * [#2097](https://github.com/ruby-grape/grape/pull/2097): Skip to set default value unless `meets_dependency?` - [@wanabe](https://github.com/wanabe).
26
+ * [#2096](https://github.com/ruby-grape/grape/pull/2096): Fix redundant dependency check - [@braktar](https://github.com/braktar).
27
+ * [#2096](https://github.com/ruby-grape/grape/pull/2098): Fix nested coercion - [@braktar](https://github.com/braktar).
28
+ * [#2102](https://github.com/ruby-grape/grape/pull/2102): Fix retaining setup blocks when remounting APIs - [@jylamont](https://github.com/jylamont).
29
+
30
+ ### 1.4.0 (2020/07/10)
31
+
32
+ #### Features
33
+
34
+ * [#1520](https://github.com/ruby-grape/grape/pull/1520): Un-deprecate stream-like objects - [@urkle](https://github.com/urkle).
35
+ * [#2060](https://github.com/ruby-grape/grape/pull/2060): Drop support for Ruby 2.4 - [@dblock](https://github.com/dblock).
36
+ * [#2060](https://github.com/ruby-grape/grape/pull/2060): Upgraded Rubocop to 0.84.0 - [@dblock](https://github.com/dblock).
37
+ * [#2077](https://github.com/ruby-grape/grape/pull/2077): Simplify logic for defining declared params - [@dnesteryuk](https://github.com/dnesteryuk).
38
+ * [#2076](https://github.com/ruby-grape/grape/pull/2076): Make route information available for hooks when the automatically generated endpoints are invoked - [@anakinj](https://github.com/anakinj).
39
+
40
+ #### Fixes
41
+
42
+ * [#2067](https://github.com/ruby-grape/grape/pull/2067): Coerce empty String to `nil` for all primitive types except `String` - [@petekinnecom](https://github.com/petekinnecom).
43
+ * [#2064](https://github.com/ruby-grape/grape/pull/2064): Fix Ruby 2.7 deprecation warning in `Grape::Middleware::Base#initialize` - [@skarger](https://github.com/skarger).
44
+ * [#2072](https://github.com/ruby-grape/grape/pull/2072): Fix `Grape.eager_load!` and `compile!` - [@stanhu](https://github.com/stanhu).
45
+ * [#2084](https://github.com/ruby-grape/grape/pull/2084): Fix memory leak in path normalization - [@fcheung](https://github.com/fcheung).
46
+
47
+ ### 1.3.3 (2020/05/23)
48
+
49
+ #### Features
50
+
51
+ * [#2048](https://github.com/ruby-grape/grape/issues/2034): Grape Enterprise support is now available [via TideLift](https://tidelift.com/subscription/request-a-demo?utm_source=rubygems-grape&utm_medium=referral&utm_campaign=enterprise) - [@dblock](https://github.com/dblock).
52
+ * [#2039](https://github.com/ruby-grape/grape/pull/2039): Travis - update rails versions - [@ericproulx](https://github.com/ericproulx).
53
+ * [#2038](https://github.com/ruby-grape/grape/pull/2038): Travis - update ruby versions - [@ericproulx](https://github.com/ericproulx).
54
+ * [#2050](https://github.com/ruby-grape/grape/pull/2050): Refactor route public_send to AttributeTranslator - [@ericproulx](https://github.com/ericproulx).
55
+
56
+ #### Fixes
57
+
58
+ * [#2049](https://github.com/ruby-grape/grape/pull/2049): Coerce an empty string to nil in case of the bool type - [@dnesteryuk](https://github.com/dnesteryuk).
59
+ * [#2043](https://github.com/ruby-grape/grape/pull/2043): Modify declared for nested array and hash - [@kadotami](https://github.com/kadotami).
60
+ * [#2040](https://github.com/ruby-grape/grape/pull/2040): Fix a regression with Array of type nil - [@ericproulx](https://github.com/ericproulx).
61
+ * [#2054](https://github.com/ruby-grape/grape/pull/2054): Coercing of nested arrays - [@dnesteryuk](https://github.com/dnesteryuk).
62
+ * [#2050](https://github.com/ruby-grape/grape/pull/2053): Fix broken multiple mounts - [@Jack12816](https://github.com/Jack12816).
63
+
64
+ ### 1.3.2 (2020/04/12)
65
+
66
+ #### Features
67
+
68
+ * [#2020](https://github.com/ruby-grape/grape/pull/2020): Reduce array allocation - [@ericproulx](https://github.com/ericproulx).
69
+ * [#2015](https://github.com/ruby-grape/grape/pull/2014): Reduce MatchData allocation - [@ericproulx](https://github.com/ericproulx).
70
+ * [#2014](https://github.com/ruby-grape/grape/pull/2014): Reduce total allocated arrays - [@ericproulx](https://github.com/ericproulx).
71
+ * [#2011](https://github.com/ruby-grape/grape/pull/2011): Reduce total retained regexes - [@ericproulx](https://github.com/ericproulx).
72
+
73
+ #### Fixes
74
+
75
+ * [#2033](https://github.com/ruby-grape/grape/pull/2033): Ensure `Float` params are correctly coerced to `BigDecimal` - [@tlconnor](https://github.com/tlconnor).
76
+ * [#2031](https://github.com/ruby-grape/grape/pull/2031): Fix a regression with an array of a custom type - [@dnesteryuk](https://github.com/dnesteryuk).
77
+ * [#2026](https://github.com/ruby-grape/grape/pull/2026): Fix a regression in `coerce_with` when coercion returns `nil` - [@misdoro](https://github.com/misdoro).
78
+ * [#2025](https://github.com/ruby-grape/grape/pull/2025): Fix Decimal type category - [@kdoya](https://github.com/kdoya).
79
+ * [#2019](https://github.com/ruby-grape/grape/pull/2019): Avoid coercing parameter with multiple types to an empty Array - [@stanhu](https://github.com/stanhu).
80
+
1
81
  ### 1.3.1 (2020/03/11)
2
82
 
3
83
  #### Features
@@ -18,7 +98,8 @@
18
98
  * [#1976](https://github.com/ruby-grape/grape/pull/1976): Ensure classes/modules listed for autoload really exist - [@dnesteryuk](https://github.com/dnesteryuk).
19
99
  * [#1971](https://github.com/ruby-grape/grape/pull/1971): Fix BigDecimal coercion - [@FlickStuart](https://github.com/FlickStuart).
20
100
  * [#1968](https://github.com/ruby-grape/grape/pull/1968): Fix args forwarding in Grape::Middleware::Stack#merge_with for ruby 2.7.0 - [@dm1try](https://github.com/dm1try).
21
- * [#1988](https://github.com/ruby-grape/grape/pull/1988): Refactored the full_messages method and stop overriding full_message - [@hosseintoussi](https://github.com/hosseintoussi).
101
+ * [#1988](https://github.com/ruby-grape/grape/pull/1988): Refactor the full_messages method and stop overriding full_message - [@hosseintoussi](https://github.com/hosseintoussi).
102
+ * [#1956](https://github.com/ruby-grape/grape/pull/1956): Comply with Rack spec, fix `undefined method [] for nil:NilClass` error when upgrading Rack - [@ioquatix](https://github.com/ioquatix).
22
103
 
23
104
  ### 1.3.0 (2020/01/11)
24
105
 
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2019 Michael Bleigh, Intridea Inc. and Contributors.
1
+ Copyright (c) 2010-2020 Michael Bleigh, Intridea Inc. and Contributors.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -12,6 +12,7 @@
12
12
  - [What is Grape?](#what-is-grape)
13
13
  - [Stable Release](#stable-release)
14
14
  - [Project Resources](#project-resources)
15
+ - [Grape for Enterprise](#grape-for-enterprise)
15
16
  - [Installation](#installation)
16
17
  - [Basic Usage](#basic-usage)
17
18
  - [Mounting](#mounting)
@@ -141,6 +142,7 @@
141
142
  - [format_response.grape](#format_responsegrape)
142
143
  - [Monitoring Products](#monitoring-products)
143
144
  - [Contributing to Grape](#contributing-to-grape)
145
+ - [Security](#security)
144
146
  - [License](#license)
145
147
  - [Copyright](#copyright)
146
148
 
@@ -154,7 +156,7 @@ content negotiation, versioning and much more.
154
156
 
155
157
  ## Stable Release
156
158
 
157
- You're reading the documentation for the stable release of Grape, **1.3.1**.
159
+ You're reading the documentation for the stable release of Grape, 1.5.1.
158
160
 
159
161
  ## Project Resources
160
162
 
@@ -163,6 +165,14 @@ You're reading the documentation for the stable release of Grape, **1.3.1**.
163
165
  * Need help? Try [Grape Google Group](http://groups.google.com/group/ruby-grape) or [Gitter](https://gitter.im/ruby-grape/grape)
164
166
  * [Follow us on Twitter](https://twitter.com/grapeframework)
165
167
 
168
+ ## Grape for Enterprise
169
+
170
+ Available as part of the Tidelift Subscription.
171
+
172
+ The maintainers of Grape are working with Tidelift to deliver commercial support and maintenance. Save time, reduce risk, and improve code health, while paying the maintainers of Grape. Click [here](https://tidelift.com/subscription/request-a-demo?utm_source=rubygems-grape&utm_medium=referral&utm_campaign=enterprise) for more details.
173
+
174
+ In 2020, we plan to use the money towards gathering Grape contributors for dinner in New York City.
175
+
166
176
  ## Installation
167
177
 
168
178
  Ruby 2.4 or newer is required.
@@ -338,9 +348,12 @@ class Web < Sinatra::Base
338
348
  end
339
349
 
340
350
  use Rack::Session::Cookie
341
- run Rack::Cascade.new [API, Web]
351
+ run Rack::Cascade.new [Web, API]
342
352
  ```
343
353
 
354
+ Note that order of loading apps using `Rack::Cascade` matters. The grape application must be last if you want to raise custom 404 errors from grape (such as `error!('Not Found',404)`). If the grape application is not last and returns 404 or 405 response, [cascade utilizes that as a signal to try the next app](https://www.rubydoc.info/gems/rack/Rack/Cascade). This may lead to undesirable behavior showing the [wrong 404 page from the wrong app](https://github.com/ruby-grape/grape/issues/1515).
355
+
356
+
344
357
  ### Rails
345
358
 
346
359
  Place API files into `app/api`. Rails expects a subdirectory that matches the name of the Ruby module and a file name that matches the name of the class. In our example, the file name location and directory for `Twitter::API` should be `app/api/twitter/api.rb`.
@@ -772,7 +785,12 @@ Available parameter builders are `Grape::Extensions::Hash::ParamBuilder`, `Grape
772
785
 
773
786
  ### Declared
774
787
 
775
- Grape allows you to access only the parameters that have been declared by your `params` block. It filters out the params that have been passed, but are not allowed. Consider the following API endpoint:
788
+ Grape allows you to access only the parameters that have been declared by your `params` block. It will:
789
+
790
+ * Filter out the params that have been passed, but are not allowed.
791
+ * Include any optional params that are declared but not passed.
792
+
793
+ Consider the following API endpoint:
776
794
 
777
795
  ````ruby
778
796
  format :json
@@ -805,9 +823,9 @@ Once we add parameters requirements, grape will start returning only the declare
805
823
  format :json
806
824
 
807
825
  params do
808
- requires :user, type: Hash do
809
- requires :first_name, type: String
810
- requires :last_name, type: String
826
+ optional :user, type: Hash do
827
+ optional :first_name, type: String
828
+ optional :last_name, type: String
811
829
  end
812
830
  end
813
831
 
@@ -835,6 +853,44 @@ curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d
835
853
  }
836
854
  ````
837
855
 
856
+ Missing params that are declared as type `Hash` or `Array` will be included.
857
+
858
+ ````ruby
859
+ format :json
860
+
861
+ params do
862
+ optional :user, type: Hash do
863
+ optional :first_name, type: String
864
+ optional :last_name, type: String
865
+ end
866
+ optional :widgets, type: Array
867
+ end
868
+
869
+ post 'users/signup' do
870
+ { 'declared_params' => declared(params) }
871
+ end
872
+ ````
873
+
874
+ **Request**
875
+
876
+ ````bash
877
+ curl -X POST -H "Content-Type: application/json" localhost:9292/users/signup -d '{}'
878
+ ````
879
+
880
+ **Response**
881
+
882
+ ````json
883
+ {
884
+ "declared_params": {
885
+ "user": {
886
+ "first_name": null,
887
+ "last_name": null
888
+ },
889
+ "widgets": []
890
+ }
891
+ }
892
+ ````
893
+
838
894
  The returned hash is an `ActiveSupport::HashWithIndifferentAccess`.
839
895
 
840
896
  The `#declared` method is not available to `before` filters, as those are evaluated prior to parameter coercion.
@@ -893,8 +949,10 @@ By default `declared(params)` includes parameters that have `nil` values. If you
893
949
  format :json
894
950
 
895
951
  params do
896
- requires :first_name, type: String
897
- optional :last_name, type: String
952
+ requires :user, type: Hash do
953
+ requires :first_name, type: String
954
+ optional :last_name, type: String
955
+ end
898
956
  end
899
957
 
900
958
  post 'users/signup' do
@@ -1047,13 +1105,13 @@ params do
1047
1105
  end
1048
1106
  ```
1049
1107
 
1050
- Note that default values will be passed through to any validation options specified.
1051
- The following example will always fail if `:color` is not explicitly provided.
1052
-
1053
1108
  Default values are eagerly evaluated. Above `:non_random_number` will evaluate to the same
1054
1109
  number for each call to the endpoint of this `params` block. To have the default evaluate
1055
1110
  lazily with each request use a lambda, like `:random_number` above.
1056
1111
 
1112
+ Note that default values will be passed through to any validation options specified.
1113
+ The following example will always fail if `:color` is not explicitly provided.
1114
+
1057
1115
  ```ruby
1058
1116
  params do
1059
1117
  optional :color, type: String, default: 'blue', values: ['red', 'green']
@@ -1980,10 +2038,10 @@ end
1980
2038
 
1981
2039
  # is NOT the same as
1982
2040
 
1983
- get ':status' do # this makes param[:status] available
2041
+ get ':status' do # this makes params[:status] available
1984
2042
  end
1985
2043
 
1986
- # This will make both param[:status_id] and param[:id] available
2044
+ # This will make both params[:status_id] and params[:id] available
1987
2045
 
1988
2046
  get 'statuses/:status_id/reviews/:id' do
1989
2047
  end
@@ -3156,17 +3214,19 @@ end
3156
3214
 
3157
3215
  Use `body false` to return `204 No Content` without any data or content-type.
3158
3216
 
3159
- You can also set the response to a file with `file`.
3217
+ You can also set the response to a file with `sendfile`. This works with the
3218
+ [Rack::Sendfile](https://www.rubydoc.info/gems/rack/Rack/Sendfile) middleware to optimally send
3219
+ the file through your web server software.
3160
3220
 
3161
3221
  ```ruby
3162
3222
  class API < Grape::API
3163
3223
  get '/' do
3164
- file '/path/to/file'
3224
+ sendfile '/path/to/file'
3165
3225
  end
3166
3226
  end
3167
3227
  ```
3168
3228
 
3169
- If you want a file to be streamed using Rack::Chunked, use `stream`.
3229
+ To stream a file in chunks use `stream`
3170
3230
 
3171
3231
  ```ruby
3172
3232
  class API < Grape::API
@@ -3176,6 +3236,26 @@ class API < Grape::API
3176
3236
  end
3177
3237
  ```
3178
3238
 
3239
+ If you want to stream non-file data use the `stream` method and a `Stream` object.
3240
+ This is an object that responds to `each` and yields for each chunk to send to the client.
3241
+ Each chunk will be sent as it is yielded instead of waiting for all of the content to be available.
3242
+
3243
+ ```ruby
3244
+ class MyStream
3245
+ def each
3246
+ yield 'part 1'
3247
+ yield 'part 2'
3248
+ yield 'part 3'
3249
+ end
3250
+ end
3251
+
3252
+ class API < Grape::API
3253
+ get '/' do
3254
+ stream MyStream.new
3255
+ end
3256
+ end
3257
+ ```
3258
+
3179
3259
  ## Authentication
3180
3260
 
3181
3261
  ### Basic and Digest Auth
@@ -3187,14 +3267,13 @@ applies to the current namespace and any children, but not parents.
3187
3267
  ```ruby
3188
3268
  http_basic do |username, password|
3189
3269
  # verify user's password here
3190
- { 'test' => 'password1' }[username] == password
3270
+ # IMPORTANT: make sure you use a comparison method which isn't prone to a timing attack
3191
3271
  end
3192
3272
  ```
3193
3273
 
3194
3274
  ```ruby
3195
3275
  http_digest({ realm: 'Test Api', opaque: 'app secret' }) do |username|
3196
3276
  # lookup the user's password here
3197
- { 'user1' => 'password1' }[username]
3198
3277
  end
3199
3278
  ```
3200
3279
 
@@ -3851,7 +3930,7 @@ Grape integrates with following third-party tools:
3851
3930
  * **Librato Metrics** - [grape-librato](https://github.com/seanmoon/grape-librato) gem
3852
3931
  * **[Skylight](https://www.skylight.io/)** - [skylight](https://github.com/skylightio/skylight-ruby) gem, [documentation](https://docs.skylight.io/grape/)
3853
3932
  * **[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)
3854
- * **[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)
3933
+ * **[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)
3855
3934
 
3856
3935
  ## Contributing to Grape
3857
3936
 
@@ -3860,10 +3939,14 @@ features and discuss issues.
3860
3939
 
3861
3940
  See [CONTRIBUTING](CONTRIBUTING.md).
3862
3941
 
3942
+ ## Security
3943
+
3944
+ See [SECURITY](SECURITY.md) for details.
3945
+
3863
3946
  ## License
3864
3947
 
3865
- MIT License. See LICENSE for details.
3948
+ MIT License. See [LICENSE](LICENSE) for details.
3866
3949
 
3867
3950
  ## Copyright
3868
3951
 
3869
- Copyright (c) 2010-2019 Michael Bleigh, Intridea Inc. and Contributors.
3952
+ Copyright (c) 2010-2020 Michael Bleigh, Intridea Inc. and Contributors.
@@ -1,6 +1,192 @@
1
1
  Upgrading Grape
2
2
  ===============
3
3
 
4
+ ### Upgrading to >= 1.5.1
5
+
6
+ #### Dependent params
7
+
8
+ If you use [dependent params](https://github.com/ruby-grape/grape#dependent-parameters) with
9
+ `Grape::Extensions::Hash::ParamBuilder`, make sure a parameter to be dependent on is set as a Symbol.
10
+ If a String is given, a parameter that other parameters depend on won't be found even if it is present.
11
+
12
+ _Correct_:
13
+ ```ruby
14
+ given :matrix do
15
+ # dependent params
16
+ end
17
+ ```
18
+
19
+ _Wrong_:
20
+ ```ruby
21
+ given 'matrix' do
22
+ # dependent params
23
+ end
24
+ ```
25
+
26
+ ### Upgrading to >= 1.5.0
27
+
28
+ Prior to 1.3.3, the `declared` helper would always return the complete params structure if `include_missing=true` was set. In 1.3.3 a regression was introduced such that a missing Hash with or without nested parameters would always resolve to `{}`.
29
+
30
+ In 1.5.0 this behavior is reverted, so the whole params structure will always be available via `declared`, regardless of whether any params are passed.
31
+
32
+ The following rules now apply to the `declared` helper when params are missing and `include_missing=true`:
33
+
34
+ * Hash params with children will resolve to a Hash with keys for each declared child.
35
+ * Hash params with no children will resolve to `{}`.
36
+ * Set params will resolve to `Set.new`.
37
+ * Array params will resolve to `[]`.
38
+ * All other params will resolve to `nil`.
39
+
40
+ #### Example
41
+
42
+ ```ruby
43
+ class Api < Grape::API
44
+ params do
45
+ optional :outer, type: Hash do
46
+ optional :inner, type: Hash do
47
+ optional :value, type: String
48
+ end
49
+ end
50
+ end
51
+ get 'example' do
52
+ declared(params, include_missing: true)
53
+ end
54
+ end
55
+ ```
56
+
57
+ ```
58
+ get '/example'
59
+ # 1.3.3 = {}
60
+ # 1.5.0 = {outer: {inner: {value:null}}}
61
+ ```
62
+
63
+ For more information see [#2103](https://github.com/ruby-grape/grape/pull/2103).
64
+
65
+ ### Upgrading to >= 1.4.0
66
+
67
+ #### Reworking stream and file and un-deprecating stream like-objects
68
+
69
+ Previously in 0.16 stream-like objects were deprecated. This release restores their functionality for use-cases other than file streaming.
70
+
71
+ This release deprecated `file` in favor of `sendfile` to better document its purpose.
72
+
73
+ To deliver a file via the Sendfile support in your web server and have the Rack::Sendfile middleware enabled. See [`Rack::Sendfile`](https://www.rubydoc.info/gems/rack/Rack/Sendfile).
74
+ ```ruby
75
+ class API < Grape::API
76
+ get '/' do
77
+ sendfile '/path/to/file'
78
+ end
79
+ end
80
+ ```
81
+
82
+ Use `stream` to stream file content in chunks.
83
+
84
+ ```ruby
85
+ class API < Grape::API
86
+ get '/' do
87
+ stream '/path/to/file'
88
+ end
89
+ end
90
+ ```
91
+
92
+ Or use `stream` to stream other kinds of content. In the following example a streamer class
93
+ streams paginated data from a database.
94
+
95
+ ```ruby
96
+ class MyObject
97
+ attr_accessor :result
98
+
99
+ def initialize(query)
100
+ @result = query
101
+ end
102
+
103
+ def each
104
+ yield '['
105
+ # Do paginated DB fetches and return each page formatted
106
+ first = false
107
+ result.find_in_batches do |records|
108
+ yield process_records(records, first)
109
+ first = false
110
+ end
111
+ yield ']'
112
+ end
113
+
114
+ def process_records(records, first)
115
+ buffer = +''
116
+ buffer << ',' unless first
117
+ buffer << records.map(&:to_json).join(',')
118
+ buffer
119
+ end
120
+ end
121
+
122
+ class API < Grape::API
123
+ get '/' do
124
+ stream MyObject.new(Sprocket.all)
125
+ end
126
+ end
127
+ ```
128
+
129
+ ### Upgrading to >= 1.3.3
130
+
131
+ #### Nil values for structures
132
+
133
+ Nil values always been a special case when dealing with types especially with the following structures:
134
+
135
+ - Array
136
+ - Hash
137
+ - Set
138
+
139
+ The behavior for these structures has change through out the latest releases. For example:
140
+
141
+ ```ruby
142
+ class Api < Grape::API
143
+ params do
144
+ require :my_param, type: Array[Integer]
145
+ end
146
+
147
+ get 'example' do
148
+ params[:my_param]
149
+ end
150
+ get '/example', params: { my_param: nil }
151
+ # 1.3.1 = []
152
+ # 1.3.2 = nil
153
+ end
154
+ ```
155
+
156
+ For now on, `nil` values stay `nil` values for all types, including arrays, sets and hashes.
157
+
158
+ If you want to have the same behavior as 1.3.1, apply a `default` validator:
159
+
160
+ ```ruby
161
+ class Api < Grape::API
162
+ params do
163
+ require :my_param, type: Array[Integer], default: []
164
+ end
165
+
166
+ get 'example' do
167
+ params[:my_param]
168
+ end
169
+ get '/example', params: { my_param: nil } # => []
170
+ end
171
+ ```
172
+
173
+ #### Default validator
174
+
175
+ Default validator is now applied for `nil` values.
176
+
177
+ ```ruby
178
+ class Api < Grape::API
179
+ params do
180
+ requires :my_param, type: Integer, default: 0
181
+ end
182
+
183
+ get 'example' do
184
+ params[:my_param]
185
+ end
186
+ get '/example', params: { my_param: nil } #=> before: nil, after: 0
187
+ end
188
+ ```
189
+
4
190
  ### Upgrading to >= 1.3.0
5
191
 
6
192
  #### Ruby
@@ -9,38 +195,87 @@ After adding dry-types, Ruby 2.4 or newer is required.
9
195
 
10
196
  #### Coercion
11
197
 
12
- [Virtus](https://github.com/solnic/virtus) has been replaced by [dry-types](https://dry-rb.org/gems/dry-types/1.2/) for parameter coercion. If your project depends on Virtus, explicitly add it to your `Gemfile`. Also, if Virtus is used for defining custom types
198
+ [Virtus](https://github.com/solnic/virtus) has been replaced by [dry-types](https://dry-rb.org/gems/dry-types/1.2/) for parameter coercion. If your project depends on Virtus outside of Grape, explicitly add it to your `Gemfile`.
199
+
200
+ Here's an example of how to migrate a custom type from Virtus to dry-types:
13
201
 
14
202
  ```ruby
15
- class User
16
- include Virtus.model
203
+ # Legacy Grape parser
204
+ class SecureUriType < Virtus::Attribute
205
+ def coerce(input)
206
+ URI.parse value
207
+ end
17
208
 
18
- attribute :id, Integer
19
- attribute :name, String
209
+ def value_coerced?(input)
210
+ value.is_a? String
211
+ end
20
212
  end
21
213
 
22
- # somewhere in your API
23
214
  params do
24
- requires :user, type: User
215
+ requires :secure_uri, type: SecureUri
25
216
  end
26
217
  ```
27
218
 
28
- Add a class-level `parse` method to the model:
219
+ To use dry-types, we need to:
29
220
 
30
- ```ruby
31
- class User
32
- include Virtus.model
221
+ 1. Remove the inheritance of `Virtus::Attribute`
222
+ 1. Rename `coerce` to `self.parse`
223
+ 1. Rename `value_coerced?` to `self.parsed?`
33
224
 
34
- attribute :id, Integer
35
- attribute :name, String
225
+ The custom type must have a class-level `parse` method to the model. A class-level `parsed?` is needed if the parsed type differs from the defined type. In the example below, since `SecureUri` is not the same as `URI::HTTPS`, `self.parsed?` is needed:
36
226
 
37
- def self.parse(attrs)
38
- new(attrs)
227
+ ```ruby
228
+ # New dry-types parser
229
+ class SecureUri
230
+ def self.parse(value)
231
+ URI.parse value
232
+ end
233
+
234
+ def self.parsed?(value)
235
+ value.is_a? URI::HTTPS
39
236
  end
40
237
  end
238
+
239
+ params do
240
+ requires :secure_uri, type: SecureUri
241
+ end
41
242
  ```
42
243
 
43
- Custom types which don't depend on Virtus don't require any changes.
244
+ #### Coercing to `FalseClass` or `TrueClass` no longer works
245
+
246
+ Previous Grape versions allowed this, though it wasn't documented:
247
+
248
+ ```ruby
249
+ requires :true_value, type: TrueClass
250
+ requires :bool_value, types: [FalseClass, TrueClass]
251
+ ```
252
+
253
+ This is no longer supported, if you do this, your values will never be valid. Instead you should do this:
254
+
255
+ ```ruby
256
+ requires :true_value, type: Boolean # in your endpoint you should validate if this is actually `true`
257
+ requires :bool_value, type: Boolean
258
+ ```
259
+
260
+ #### Ensure that Array types have explicit coercions
261
+
262
+ Unlike Virtus, dry-types does not perform any implict coercions. If you have any uses of `Array[String]`, `Array[Integer]`, etc. be sure they use a `coerce_with` block. For example:
263
+
264
+ ```ruby
265
+ requires :values, type: Array[String]
266
+ ```
267
+
268
+ It's quite common to pass a comma-separated list, such as `tag1,tag2` as `values`. Previously Virtus would implicitly coerce this to `Array(values)` so that `["tag1,tag2"]` would pass the type checks, but with `dry-types` the values are no longer coerced for you. To fix this, you might do:
269
+
270
+ ```ruby
271
+ requires :values, type: Array[String], coerce_with: ->(val) { val.split(',').map(&:strip) }
272
+ ```
273
+
274
+ Likewise, for `Array[Integer]`, you might do:
275
+
276
+ ```ruby
277
+ requires :values, type: Array[Integer], coerce_with: ->(val) { val.split(',').map(&:strip).map(&:to_i) }
278
+ ```
44
279
 
45
280
  For more information see [#1920](https://github.com/ruby-grape/grape/pull/1920).
46
281
 
@@ -97,12 +332,9 @@ In order to make obtaining the name of a mounted class simpler, we've delegated
97
332
 
98
333
  ##### Patching the class
99
334
 
100
- In an effort to make APIs re-mountable, The class `Grape::API` no longer refers to an API instance,
101
- rather, what used to be `Grape::API` is now `Grape::API::Instance` and `Grape::API` was replaced
102
- with a class that can contain several instances of `Grape::API`.
335
+ In an effort to make APIs re-mountable, The class `Grape::API` no longer refers to an API instance, rather, what used to be `Grape::API` is now `Grape::API::Instance` and `Grape::API` was replaced with a class that can contain several instances of `Grape::API`.
103
336
 
104
- This changes were done in such a way that no code-changes should be required.
105
- However, if experiencing problems, or relying on private methods and internal behaviour too deeply, it is possible to restore the prior behaviour by replacing the references from `Grape::API` to `Grape::API::Instance`.
337
+ This changes were done in such a way that no code-changes should be required. However, if experiencing problems, or relying on private methods and internal behaviour too deeply, it is possible to restore the prior behaviour by replacing the references from `Grape::API` to `Grape::API::Instance`.
106
338
 
107
339
  Note, this is particularly relevant if you are opening the class `Grape::API` for modification.
108
340
 
@@ -125,15 +357,20 @@ end
125
357
 
126
358
  After the patch, the mounted API is no longer a Named class inheriting from `Grape::API`, it is an anonymous class
127
359
  which inherit from `Grape::API::Instance`.
360
+
128
361
  What this means in practice, is:
362
+
129
363
  - Generally: you can access the named class from the instance calling the getter `base`.
130
- - In particular: If you need the `name`, you can use `base`.`name`
364
+ - In particular: If you need the `name`, you can use `base`.`name`.
131
365
 
132
366
  **Deprecated**
367
+
133
368
  ```ruby
134
369
  payload[:endpoint].options[:for].name
135
370
  ```
371
+
136
372
  **New**
373
+
137
374
  ```ruby
138
375
  payload[:endpoint].options[:for].base.name
139
376
  ```
@@ -224,8 +461,7 @@ See [#1610](https://github.com/ruby-grape/grape/pull/1610) for more information.
224
461
 
225
462
  #### The `except`, `except_message`, and `proc` options of the `values` validator are deprecated.
226
463
 
227
- The new `except_values` validator should be used in place of the `except` and `except_message` options of
228
- the `values` validator.
464
+ The new `except_values` validator should be used in place of the `except` and `except_message` options of the `values` validator.
229
465
 
230
466
  Arity one Procs may now be used directly as the `values` option to explicitly test param values.
231
467
 
@@ -301,9 +537,7 @@ get '/example' #=> before: 405, after: 404
301
537
 
302
538
  #### Removed param processing from built-in OPTIONS handler
303
539
 
304
- When a request is made to the built-in `OPTIONS` handler, only the `before` and `after`
305
- callbacks associated with the resource will be run. The `before_validation` and
306
- `after_validation` callbacks and parameter validations will be skipped.
540
+ When a request is made to the built-in `OPTIONS` handler, only the `before` and `after` callbacks associated with the resource will be run. The `before_validation` and `after_validation` callbacks and parameter validations will be skipped.
307
541
 
308
542
  See [#1505](https://github.com/ruby-grape/grape/pull/1505) for more information.
309
543
 
@@ -324,8 +558,7 @@ See [#1510](https://github.com/ruby-grape/grape/pull/1510) for more information.
324
558
 
325
559
  #### The default status code for DELETE is now 204 instead of 200.
326
560
 
327
- Breaking change: Sets the default response status code for a delete request to 204.
328
- A status of 204 makes the response more distinguishable and therefore easier to handle on the client side, particularly because a DELETE request typically returns an empty body as the resource was deleted or voided.
561
+ Breaking change: Sets the default response status code for a delete request to 204. A status of 204 makes the response more distinguishable and therefore easier to handle on the client side, particularly because a DELETE request typically returns an empty body as the resource was deleted or voided.
329
562
 
330
563
  To achieve the old behavior, one has to set it explicitly:
331
564
  ```ruby
@@ -503,18 +736,14 @@ See [#1114](https://github.com/ruby-grape/grape/pull/1114) for more information.
503
736
 
504
737
  #### Bypasses formatters when status code indicates no content
505
738
 
506
- To be consistent with rack and it's handling of standard responses
507
- associated with no content, both default and custom formatters will now
739
+ To be consistent with rack and it's handling of standard responses associated with no content, both default and custom formatters will now
508
740
  be bypassed when processing responses for status codes defined [by rack](https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L567)
509
741
 
510
742
  See [#1190](https://github.com/ruby-grape/grape/pull/1190) for more information.
511
743
 
512
744
  #### Redirects respond as plain text with message
513
745
 
514
- `#redirect` now uses `text/plain` regardless of whether that format has
515
- been enabled. This prevents formatters from attempting to serialize the
516
- message body and allows for a descriptive message body to be provided - and
517
- optionally overridden - that better fulfills the theme of the HTTP spec.
746
+ `#redirect` now uses `text/plain` regardless of whether that format has been enabled. This prevents formatters from attempting to serialize the message body and allows for a descriptive message body to be provided - and optionally overridden - that better fulfills the theme of the HTTP spec.
518
747
 
519
748
  See [#1194](https://github.com/ruby-grape/grape/pull/1194) for more information.
520
749
 
@@ -548,10 +777,7 @@ end
548
777
 
549
778
  See [#1029](https://github.com/ruby-grape/grape/pull/1029) for more information.
550
779
 
551
- There is a known issue because of this change. When Grape is used with an older
552
- than 1.2.4 version of [warden](https://github.com/hassox/warden) there may be raised
553
- the following exception having the [rack-mount](https://github.com/jm/rack-mount) gem's
554
- lines as last ones in the backtrace:
780
+ There is a known issue because of this change. When Grape is used with an older than 1.2.4 version of [warden](https://github.com/hassox/warden) there may be raised the following exception having the [rack-mount](https://github.com/jm/rack-mount) gem's lines as last ones in the backtrace:
555
781
 
556
782
  ```
557
783
  NoMethodError: undefined method `[]' for nil:NilClass