grape 1.1.0 → 1.5.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +278 -44
- data/LICENSE +1 -1
- data/README.md +514 -69
- data/UPGRADING.md +424 -17
- data/grape.gemspec +13 -2
- data/lib/grape.rb +104 -71
- data/lib/grape/api.rb +138 -175
- data/lib/grape/api/helpers.rb +2 -0
- data/lib/grape/api/instance.rb +283 -0
- data/lib/grape/config.rb +34 -0
- data/lib/grape/content_types.rb +34 -0
- data/lib/grape/cookies.rb +2 -0
- data/lib/grape/dsl/api.rb +2 -0
- data/lib/grape/dsl/callbacks.rb +22 -0
- data/lib/grape/dsl/configuration.rb +2 -0
- data/lib/grape/dsl/desc.rb +41 -7
- data/lib/grape/dsl/headers.rb +2 -0
- data/lib/grape/dsl/helpers.rb +5 -2
- data/lib/grape/dsl/inside_route.rb +92 -49
- data/lib/grape/dsl/logger.rb +2 -0
- data/lib/grape/dsl/middleware.rb +9 -0
- data/lib/grape/dsl/parameters.rb +25 -14
- data/lib/grape/dsl/request_response.rb +4 -2
- data/lib/grape/dsl/routing.rb +17 -10
- data/lib/grape/dsl/settings.rb +7 -1
- data/lib/grape/dsl/validations.rb +24 -4
- data/lib/grape/eager_load.rb +20 -0
- data/lib/grape/endpoint.rb +59 -35
- data/lib/grape/error_formatter.rb +4 -2
- data/lib/grape/error_formatter/base.rb +2 -0
- data/lib/grape/error_formatter/json.rb +2 -0
- data/lib/grape/error_formatter/txt.rb +2 -0
- data/lib/grape/error_formatter/xml.rb +2 -0
- data/lib/grape/exceptions/base.rb +20 -14
- data/lib/grape/exceptions/empty_message_body.rb +11 -0
- data/lib/grape/exceptions/incompatible_option_values.rb +2 -0
- data/lib/grape/exceptions/invalid_accept_header.rb +2 -0
- data/lib/grape/exceptions/invalid_formatter.rb +2 -0
- data/lib/grape/exceptions/invalid_message_body.rb +2 -0
- data/lib/grape/exceptions/invalid_response.rb +11 -0
- data/lib/grape/exceptions/invalid_version_header.rb +2 -0
- data/lib/grape/exceptions/invalid_versioner_option.rb +2 -0
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -0
- data/lib/grape/exceptions/method_not_allowed.rb +2 -0
- data/lib/grape/exceptions/missing_group_type.rb +2 -0
- data/lib/grape/exceptions/missing_mime_type.rb +2 -0
- data/lib/grape/exceptions/missing_option.rb +2 -0
- data/lib/grape/exceptions/missing_vendor_option.rb +2 -0
- data/lib/grape/exceptions/unknown_options.rb +2 -0
- data/lib/grape/exceptions/unknown_parameter.rb +2 -0
- data/lib/grape/exceptions/unknown_validator.rb +2 -0
- data/lib/grape/exceptions/unsupported_group_type.rb +2 -0
- data/lib/grape/exceptions/validation.rb +4 -2
- data/lib/grape/exceptions/validation_array_errors.rb +2 -0
- data/lib/grape/exceptions/validation_errors.rb +16 -13
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
- data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
- data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
- data/lib/grape/extensions/hash.rb +2 -0
- data/lib/grape/extensions/hashie/mash.rb +2 -0
- data/lib/grape/formatter.rb +5 -3
- data/lib/grape/formatter/json.rb +2 -0
- data/lib/grape/formatter/serializable_hash.rb +2 -0
- data/lib/grape/formatter/txt.rb +2 -0
- data/lib/grape/formatter/xml.rb +2 -0
- data/lib/grape/http/headers.rb +50 -18
- data/lib/grape/locale/en.yml +3 -1
- data/lib/grape/middleware/auth/base.rb +7 -7
- data/lib/grape/middleware/auth/dsl.rb +2 -0
- data/lib/grape/middleware/auth/strategies.rb +2 -0
- data/lib/grape/middleware/auth/strategy_info.rb +2 -0
- data/lib/grape/middleware/base.rb +10 -7
- data/lib/grape/middleware/error.rb +21 -16
- data/lib/grape/middleware/filter.rb +2 -0
- data/lib/grape/middleware/formatter.rb +8 -6
- data/lib/grape/middleware/globals.rb +2 -0
- data/lib/grape/middleware/helpers.rb +12 -0
- data/lib/grape/middleware/stack.rb +13 -3
- data/lib/grape/middleware/versioner.rb +2 -0
- data/lib/grape/middleware/versioner/accept_version_header.rb +2 -0
- data/lib/grape/middleware/versioner/header.rb +10 -8
- data/lib/grape/middleware/versioner/param.rb +3 -1
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +4 -1
- data/lib/grape/middleware/versioner/path.rb +3 -1
- data/lib/grape/namespace.rb +14 -2
- data/lib/grape/parser.rb +4 -2
- data/lib/grape/parser/json.rb +3 -1
- data/lib/grape/parser/xml.rb +3 -1
- data/lib/grape/path.rb +15 -3
- data/lib/grape/presenters/presenter.rb +2 -0
- data/lib/grape/request.rb +19 -10
- data/lib/grape/router.rb +30 -29
- data/lib/grape/router/attribute_translator.rb +41 -8
- data/lib/grape/router/pattern.rb +20 -16
- data/lib/grape/router/route.rb +14 -28
- data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
- data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
- data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
- data/lib/grape/util/base_inheritable.rb +43 -0
- data/lib/grape/util/cache.rb +20 -0
- data/lib/grape/util/endpoint_configuration.rb +8 -0
- data/lib/grape/util/env.rb +19 -17
- data/lib/grape/util/inheritable_setting.rb +2 -0
- data/lib/grape/util/inheritable_values.rb +7 -25
- data/lib/grape/util/json.rb +2 -0
- data/lib/grape/util/lazy_block.rb +27 -0
- data/lib/grape/util/lazy_object.rb +43 -0
- data/lib/grape/util/lazy_value.rb +98 -0
- data/lib/grape/util/registrable.rb +2 -0
- data/lib/grape/util/reverse_stackable_values.rb +10 -35
- data/lib/grape/util/stackable_values.rb +21 -34
- data/lib/grape/util/strict_hash_configuration.rb +2 -0
- data/lib/grape/util/xml.rb +2 -0
- data/lib/grape/validations.rb +2 -0
- data/lib/grape/validations/attributes_iterator.rb +16 -6
- data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
- data/lib/grape/validations/params_scope.rb +51 -30
- data/lib/grape/validations/single_attribute_iterator.rb +24 -0
- data/lib/grape/validations/types.rb +13 -38
- data/lib/grape/validations/types/array_coercer.rb +65 -0
- data/lib/grape/validations/types/build_coercer.rb +47 -49
- data/lib/grape/validations/types/custom_type_coercer.rb +29 -51
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
- data/lib/grape/validations/types/dry_type_coercer.rb +76 -0
- data/lib/grape/validations/types/file.rb +22 -18
- data/lib/grape/validations/types/invalid_value.rb +24 -0
- data/lib/grape/validations/types/json.rb +46 -39
- data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
- data/lib/grape/validations/types/primitive_coercer.rb +67 -0
- data/lib/grape/validations/types/set_coercer.rb +40 -0
- data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
- data/lib/grape/validations/validator_factory.rb +8 -11
- data/lib/grape/validations/validators/all_or_none.rb +8 -13
- data/lib/grape/validations/validators/allow_blank.rb +3 -1
- data/lib/grape/validations/validators/as.rb +5 -4
- data/lib/grape/validations/validators/at_least_one_of.rb +7 -13
- data/lib/grape/validations/validators/base.rb +20 -16
- data/lib/grape/validations/validators/coerce.rb +46 -29
- data/lib/grape/validations/validators/default.rb +6 -6
- data/lib/grape/validations/validators/exactly_one_of.rb +10 -23
- data/lib/grape/validations/validators/except_values.rb +4 -2
- data/lib/grape/validations/validators/multiple_params_base.rb +17 -10
- data/lib/grape/validations/validators/mutual_exclusion.rb +8 -18
- data/lib/grape/validations/validators/presence.rb +3 -1
- data/lib/grape/validations/validators/regexp.rb +4 -2
- data/lib/grape/validations/validators/same_as.rb +26 -0
- data/lib/grape/validations/validators/values.rb +18 -6
- data/lib/grape/version.rb +3 -1
- data/spec/grape/api/custom_validations_spec.rb +5 -3
- data/spec/grape/api/deeply_included_options_spec.rb +2 -0
- data/spec/grape/api/defines_boolean_in_params_spec.rb +39 -0
- data/spec/grape/api/inherited_helpers_spec.rb +2 -0
- data/spec/grape/api/instance_spec.rb +104 -0
- data/spec/grape/api/invalid_format_spec.rb +2 -0
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/nested_helpers_spec.rb +2 -0
- data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/parameters_modification_spec.rb +3 -1
- data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
- data/spec/grape/api/recognize_path_spec.rb +2 -0
- data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
- data/spec/grape/api/routes_with_requirements_spec.rb +61 -0
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +2 -0
- data/spec/grape/api/shared_helpers_spec.rb +2 -0
- data/spec/grape/api_remount_spec.rb +473 -0
- data/spec/grape/api_spec.rb +565 -12
- data/spec/grape/config_spec.rb +19 -0
- data/spec/grape/dsl/callbacks_spec.rb +2 -0
- data/spec/grape/dsl/configuration_spec.rb +2 -0
- data/spec/grape/dsl/desc_spec.rb +42 -16
- data/spec/grape/dsl/headers_spec.rb +2 -0
- data/spec/grape/dsl/helpers_spec.rb +4 -2
- data/spec/grape/dsl/inside_route_spec.rb +184 -33
- data/spec/grape/dsl/logger_spec.rb +2 -0
- data/spec/grape/dsl/middleware_spec.rb +10 -0
- data/spec/grape/dsl/parameters_spec.rb +2 -0
- data/spec/grape/dsl/request_response_spec.rb +2 -0
- data/spec/grape/dsl/routing_spec.rb +12 -0
- data/spec/grape/dsl/settings_spec.rb +2 -0
- data/spec/grape/dsl/validations_spec.rb +2 -0
- data/spec/grape/endpoint/declared_spec.rb +601 -0
- data/spec/grape/endpoint_spec.rb +53 -523
- data/spec/grape/entity_spec.rb +9 -1
- data/spec/grape/exceptions/base_spec.rb +67 -0
- data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -0
- data/spec/grape/exceptions/invalid_response_spec.rb +13 -0
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -0
- data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
- data/spec/grape/exceptions/missing_option_spec.rb +2 -0
- data/spec/grape/exceptions/unknown_options_spec.rb +2 -0
- data/spec/grape/exceptions/unknown_validator_spec.rb +2 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +8 -4
- data/spec/grape/exceptions/validation_spec.rb +3 -1
- data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
- data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
- data/spec/grape/integration/rack_sendfile_spec.rb +14 -8
- data/spec/grape/integration/rack_spec.rb +25 -7
- data/spec/grape/loading_spec.rb +2 -0
- data/spec/grape/middleware/auth/base_spec.rb +2 -0
- data/spec/grape/middleware/auth/dsl_spec.rb +5 -3
- data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
- data/spec/grape/middleware/base_spec.rb +10 -0
- data/spec/grape/middleware/error_spec.rb +3 -1
- data/spec/grape/middleware/exception_spec.rb +4 -2
- data/spec/grape/middleware/formatter_spec.rb +33 -16
- data/spec/grape/middleware/globals_spec.rb +2 -0
- data/spec/grape/middleware/stack_spec.rb +12 -0
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
- data/spec/grape/middleware/versioner/header_spec.rb +9 -1
- data/spec/grape/middleware/versioner/param_spec.rb +3 -1
- data/spec/grape/middleware/versioner/path_spec.rb +3 -1
- data/spec/grape/middleware/versioner_spec.rb +2 -0
- data/spec/grape/named_api_spec.rb +21 -0
- data/spec/grape/parser_spec.rb +7 -5
- data/spec/grape/path_spec.rb +6 -4
- data/spec/grape/presenters/presenter_spec.rb +2 -0
- data/spec/grape/request_spec.rb +26 -0
- data/spec/grape/util/inheritable_setting_spec.rb +2 -0
- data/spec/grape/util/inheritable_values_spec.rb +2 -0
- data/spec/grape/util/reverse_stackable_values_spec.rb +2 -0
- data/spec/grape/util/stackable_values_spec.rb +3 -1
- data/spec/grape/util/strict_hash_configuration_spec.rb +2 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
- data/spec/grape/validations/instance_behaivour_spec.rb +5 -3
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +41 -0
- data/spec/grape/validations/params_scope_spec.rb +213 -9
- data/spec/grape/validations/single_attribute_iterator_spec.rb +58 -0
- data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
- data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
- data/spec/grape/validations/types_spec.rb +9 -36
- data/spec/grape/validations/validators/all_or_none_spec.rb +140 -30
- data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +175 -29
- data/spec/grape/validations/validators/coerce_spec.rb +476 -135
- data/spec/grape/validations/validators/default_spec.rb +172 -0
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +204 -38
- data/spec/grape/validations/validators/except_values_spec.rb +4 -1
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +186 -27
- data/spec/grape/validations/validators/presence_spec.rb +30 -0
- data/spec/grape/validations/validators/regexp_spec.rb +2 -0
- data/spec/grape/validations/validators/same_as_spec.rb +65 -0
- data/spec/grape/validations/validators/values_spec.rb +30 -5
- data/spec/grape/validations_spec.rb +388 -50
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/integration/multi_json/json_spec.rb +2 -0
- data/spec/integration/multi_xml/xml_spec.rb +2 -0
- data/spec/shared/versioning_examples.rb +22 -20
- data/spec/spec_helper.rb +12 -1
- data/spec/support/basic_auth_encode_helpers.rb +2 -0
- data/spec/support/chunks.rb +14 -0
- data/spec/support/content_type_helpers.rb +2 -0
- data/spec/support/eager_load.rb +19 -0
- data/spec/support/endpoint_faker.rb +2 -0
- data/spec/support/file_streamer.rb +2 -0
- data/spec/support/integer_helpers.rb +2 -0
- data/spec/support/versioned_helpers.rb +8 -8
- metadata +86 -48
- data/Appraisals +0 -32
- data/Dangerfile +0 -2
- data/Gemfile +0 -33
- data/Gemfile.lock +0 -231
- data/Guardfile +0 -10
- data/RELEASING.md +0 -111
- data/Rakefile +0 -25
- data/benchmark/simple.rb +0 -27
- data/benchmark/simple_with_type_coercer.rb +0 -22
- data/gemfiles/multi_json.gemfile +0 -35
- data/gemfiles/multi_xml.gemfile +0 -35
- data/gemfiles/rack_1.5.2.gemfile +0 -35
- data/gemfiles/rack_edge.gemfile +0 -35
- data/gemfiles/rails_3.gemfile +0 -36
- data/gemfiles/rails_4.gemfile +0 -35
- data/gemfiles/rails_5.gemfile +0 -35
- data/gemfiles/rails_edge.gemfile +0 -35
- data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
- data/lib/grape/util/content_types.rb +0 -26
- data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
- data/pkg/grape-0.17.0.gem +0 -0
- data/pkg/grape-0.19.0.gem +0 -0
data/UPGRADING.md
CHANGED
@@ -1,6 +1,424 @@
|
|
1
1
|
Upgrading Grape
|
2
2
|
===============
|
3
3
|
|
4
|
+
|
5
|
+
### Upgrading to >= 1.5.3
|
6
|
+
|
7
|
+
### Nil value and coercion
|
8
|
+
|
9
|
+
Prior to 1.2.5 version passing a `nil` value for a parameter with a custom coercer would invoke the coercer, and not passing a parameter would not invoke it.
|
10
|
+
This behavior was not tested or documented. Version 1.3.0 quietly changed this behavior, in such that `nil` values skipped the coercion. Version 1.5.3 fixes and documents this as follows:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
class Api < Grape::API
|
14
|
+
params do
|
15
|
+
optional :value, type: Integer, coerce_with: ->(val) { val || 0 }
|
16
|
+
end
|
17
|
+
|
18
|
+
get 'example' do
|
19
|
+
params[:my_param]
|
20
|
+
end
|
21
|
+
get '/example', params: { value: nil }
|
22
|
+
# 1.5.2 = nil
|
23
|
+
# 1.5.3 = 0
|
24
|
+
get '/example', params: {}
|
25
|
+
# 1.5.2 = nil
|
26
|
+
# 1.5.3 = nil
|
27
|
+
end
|
28
|
+
```
|
29
|
+
See [#2164](https://github.com/ruby-grape/grape/pull/2164) for more information.
|
30
|
+
|
31
|
+
### Upgrading to >= 1.5.1
|
32
|
+
|
33
|
+
#### Dependent params
|
34
|
+
|
35
|
+
If you use [dependent params](https://github.com/ruby-grape/grape#dependent-parameters) with
|
36
|
+
`Grape::Extensions::Hash::ParamBuilder`, make sure a parameter to be dependent on is set as a Symbol.
|
37
|
+
If a String is given, a parameter that other parameters depend on won't be found even if it is present.
|
38
|
+
|
39
|
+
_Correct_:
|
40
|
+
```ruby
|
41
|
+
given :matrix do
|
42
|
+
# dependent params
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
_Wrong_:
|
47
|
+
```ruby
|
48
|
+
given 'matrix' do
|
49
|
+
# dependent params
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
### Upgrading to >= 1.5.0
|
54
|
+
|
55
|
+
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 `{}`.
|
56
|
+
|
57
|
+
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.
|
58
|
+
|
59
|
+
The following rules now apply to the `declared` helper when params are missing and `include_missing=true`:
|
60
|
+
|
61
|
+
* Hash params with children will resolve to a Hash with keys for each declared child.
|
62
|
+
* Hash params with no children will resolve to `{}`.
|
63
|
+
* Set params will resolve to `Set.new`.
|
64
|
+
* Array params will resolve to `[]`.
|
65
|
+
* All other params will resolve to `nil`.
|
66
|
+
|
67
|
+
#### Example
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
class Api < Grape::API
|
71
|
+
params do
|
72
|
+
optional :outer, type: Hash do
|
73
|
+
optional :inner, type: Hash do
|
74
|
+
optional :value, type: String
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
get 'example' do
|
79
|
+
declared(params, include_missing: true)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
```
|
85
|
+
get '/example'
|
86
|
+
# 1.3.3 = {}
|
87
|
+
# 1.5.0 = {outer: {inner: {value:null}}}
|
88
|
+
```
|
89
|
+
|
90
|
+
For more information see [#2103](https://github.com/ruby-grape/grape/pull/2103).
|
91
|
+
|
92
|
+
### Upgrading to >= 1.4.0
|
93
|
+
|
94
|
+
#### Reworking stream and file and un-deprecating stream like-objects
|
95
|
+
|
96
|
+
Previously in 0.16 stream-like objects were deprecated. This release restores their functionality for use-cases other than file streaming.
|
97
|
+
|
98
|
+
This release deprecated `file` in favor of `sendfile` to better document its purpose.
|
99
|
+
|
100
|
+
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).
|
101
|
+
```ruby
|
102
|
+
class API < Grape::API
|
103
|
+
get '/' do
|
104
|
+
sendfile '/path/to/file'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
Use `stream` to stream file content in chunks.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
class API < Grape::API
|
113
|
+
get '/' do
|
114
|
+
stream '/path/to/file'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
Or use `stream` to stream other kinds of content. In the following example a streamer class
|
120
|
+
streams paginated data from a database.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
class MyObject
|
124
|
+
attr_accessor :result
|
125
|
+
|
126
|
+
def initialize(query)
|
127
|
+
@result = query
|
128
|
+
end
|
129
|
+
|
130
|
+
def each
|
131
|
+
yield '['
|
132
|
+
# Do paginated DB fetches and return each page formatted
|
133
|
+
first = false
|
134
|
+
result.find_in_batches do |records|
|
135
|
+
yield process_records(records, first)
|
136
|
+
first = false
|
137
|
+
end
|
138
|
+
yield ']'
|
139
|
+
end
|
140
|
+
|
141
|
+
def process_records(records, first)
|
142
|
+
buffer = +''
|
143
|
+
buffer << ',' unless first
|
144
|
+
buffer << records.map(&:to_json).join(',')
|
145
|
+
buffer
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
class API < Grape::API
|
150
|
+
get '/' do
|
151
|
+
stream MyObject.new(Sprocket.all)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
```
|
155
|
+
|
156
|
+
### Upgrading to >= 1.3.3
|
157
|
+
|
158
|
+
#### Nil values for structures
|
159
|
+
|
160
|
+
Nil values always been a special case when dealing with types especially with the following structures:
|
161
|
+
|
162
|
+
- Array
|
163
|
+
- Hash
|
164
|
+
- Set
|
165
|
+
|
166
|
+
The behavior for these structures has change through out the latest releases. For example:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
class Api < Grape::API
|
170
|
+
params do
|
171
|
+
require :my_param, type: Array[Integer]
|
172
|
+
end
|
173
|
+
|
174
|
+
get 'example' do
|
175
|
+
params[:my_param]
|
176
|
+
end
|
177
|
+
get '/example', params: { my_param: nil }
|
178
|
+
# 1.3.1 = []
|
179
|
+
# 1.3.2 = nil
|
180
|
+
end
|
181
|
+
```
|
182
|
+
|
183
|
+
For now on, `nil` values stay `nil` values for all types, including arrays, sets and hashes.
|
184
|
+
|
185
|
+
If you want to have the same behavior as 1.3.1, apply a `default` validator:
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
class Api < Grape::API
|
189
|
+
params do
|
190
|
+
require :my_param, type: Array[Integer], default: []
|
191
|
+
end
|
192
|
+
|
193
|
+
get 'example' do
|
194
|
+
params[:my_param]
|
195
|
+
end
|
196
|
+
get '/example', params: { my_param: nil } # => []
|
197
|
+
end
|
198
|
+
```
|
199
|
+
|
200
|
+
#### Default validator
|
201
|
+
|
202
|
+
Default validator is now applied for `nil` values.
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
class Api < Grape::API
|
206
|
+
params do
|
207
|
+
requires :my_param, type: Integer, default: 0
|
208
|
+
end
|
209
|
+
|
210
|
+
get 'example' do
|
211
|
+
params[:my_param]
|
212
|
+
end
|
213
|
+
get '/example', params: { my_param: nil } #=> before: nil, after: 0
|
214
|
+
end
|
215
|
+
```
|
216
|
+
|
217
|
+
### Upgrading to >= 1.3.0
|
218
|
+
|
219
|
+
#### Ruby
|
220
|
+
|
221
|
+
After adding dry-types, Ruby 2.4 or newer is required.
|
222
|
+
|
223
|
+
#### Coercion
|
224
|
+
|
225
|
+
[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`.
|
226
|
+
|
227
|
+
Here's an example of how to migrate a custom type from Virtus to dry-types:
|
228
|
+
|
229
|
+
```ruby
|
230
|
+
# Legacy Grape parser
|
231
|
+
class SecureUriType < Virtus::Attribute
|
232
|
+
def coerce(input)
|
233
|
+
URI.parse value
|
234
|
+
end
|
235
|
+
|
236
|
+
def value_coerced?(input)
|
237
|
+
value.is_a? String
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
params do
|
242
|
+
requires :secure_uri, type: SecureUri
|
243
|
+
end
|
244
|
+
```
|
245
|
+
|
246
|
+
To use dry-types, we need to:
|
247
|
+
|
248
|
+
1. Remove the inheritance of `Virtus::Attribute`
|
249
|
+
1. Rename `coerce` to `self.parse`
|
250
|
+
1. Rename `value_coerced?` to `self.parsed?`
|
251
|
+
|
252
|
+
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:
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
# New dry-types parser
|
256
|
+
class SecureUri
|
257
|
+
def self.parse(value)
|
258
|
+
URI.parse value
|
259
|
+
end
|
260
|
+
|
261
|
+
def self.parsed?(value)
|
262
|
+
value.is_a? URI::HTTPS
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
params do
|
267
|
+
requires :secure_uri, type: SecureUri
|
268
|
+
end
|
269
|
+
```
|
270
|
+
|
271
|
+
#### Coercing to `FalseClass` or `TrueClass` no longer works
|
272
|
+
|
273
|
+
Previous Grape versions allowed this, though it wasn't documented:
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
requires :true_value, type: TrueClass
|
277
|
+
requires :bool_value, types: [FalseClass, TrueClass]
|
278
|
+
```
|
279
|
+
|
280
|
+
This is no longer supported, if you do this, your values will never be valid. Instead you should do this:
|
281
|
+
|
282
|
+
```ruby
|
283
|
+
requires :true_value, type: Boolean # in your endpoint you should validate if this is actually `true`
|
284
|
+
requires :bool_value, type: Boolean
|
285
|
+
```
|
286
|
+
|
287
|
+
#### Ensure that Array types have explicit coercions
|
288
|
+
|
289
|
+
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:
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
requires :values, type: Array[String]
|
293
|
+
```
|
294
|
+
|
295
|
+
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:
|
296
|
+
|
297
|
+
```ruby
|
298
|
+
requires :values, type: Array[String], coerce_with: ->(val) { val.split(',').map(&:strip) }
|
299
|
+
```
|
300
|
+
|
301
|
+
Likewise, for `Array[Integer]`, you might do:
|
302
|
+
|
303
|
+
```ruby
|
304
|
+
requires :values, type: Array[Integer], coerce_with: ->(val) { val.split(',').map(&:strip).map(&:to_i) }
|
305
|
+
```
|
306
|
+
|
307
|
+
For more information see [#1920](https://github.com/ruby-grape/grape/pull/1920).
|
308
|
+
|
309
|
+
### Upgrading to >= 1.2.4
|
310
|
+
|
311
|
+
#### Headers in `error!` call
|
312
|
+
|
313
|
+
Headers in `error!` will be merged with `headers` hash. If any header need to be cleared on `error!` call, make sure to move it to the `after` block.
|
314
|
+
|
315
|
+
```ruby
|
316
|
+
class SampleApi < Grape::API
|
317
|
+
before do
|
318
|
+
header 'X-Before-Header', 'before_call'
|
319
|
+
end
|
320
|
+
|
321
|
+
get 'ping' do
|
322
|
+
header 'X-App-Header', 'on_call'
|
323
|
+
error! :pong, 400, 'X-Error-Details' => 'Invalid token'
|
324
|
+
end
|
325
|
+
end
|
326
|
+
```
|
327
|
+
**Former behaviour**
|
328
|
+
```ruby
|
329
|
+
response.headers['X-Before-Header'] # => nil
|
330
|
+
response.headers['X-App-Header'] # => nil
|
331
|
+
response.headers['X-Error-Details'] # => Invalid token
|
332
|
+
```
|
333
|
+
|
334
|
+
**Current behaviour**
|
335
|
+
```ruby
|
336
|
+
response.headers['X-Before-Header'] # => 'before_call'
|
337
|
+
response.headers['X-App-Header'] # => 'on_call'
|
338
|
+
response.headers['X-Error-Details'] # => Invalid token
|
339
|
+
```
|
340
|
+
|
341
|
+
### Upgrading to >= 1.2.1
|
342
|
+
|
343
|
+
#### Obtaining the name of a mounted class
|
344
|
+
|
345
|
+
In order to make obtaining the name of a mounted class simpler, we've delegated `.to_s` to `base.name`
|
346
|
+
|
347
|
+
**Deprecated in 1.2.0**
|
348
|
+
```ruby
|
349
|
+
payload[:endpoint].options[:for].name
|
350
|
+
```
|
351
|
+
**New**
|
352
|
+
```ruby
|
353
|
+
payload[:endpoint].options[:for].to_s
|
354
|
+
```
|
355
|
+
|
356
|
+
### Upgrading to >= 1.2.0
|
357
|
+
|
358
|
+
#### Changes in the Grape::API class
|
359
|
+
|
360
|
+
##### Patching the class
|
361
|
+
|
362
|
+
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`.
|
363
|
+
|
364
|
+
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`.
|
365
|
+
|
366
|
+
Note, this is particularly relevant if you are opening the class `Grape::API` for modification.
|
367
|
+
|
368
|
+
**Deprecated**
|
369
|
+
```ruby
|
370
|
+
class Grape::API
|
371
|
+
# your patched logic
|
372
|
+
...
|
373
|
+
end
|
374
|
+
```
|
375
|
+
**New**
|
376
|
+
```ruby
|
377
|
+
class Grape::API::Instance
|
378
|
+
# your patched logic
|
379
|
+
...
|
380
|
+
end
|
381
|
+
```
|
382
|
+
|
383
|
+
##### `name` (and other caveats) of the mounted API
|
384
|
+
|
385
|
+
After the patch, the mounted API is no longer a Named class inheriting from `Grape::API`, it is an anonymous class
|
386
|
+
which inherit from `Grape::API::Instance`.
|
387
|
+
|
388
|
+
What this means in practice, is:
|
389
|
+
|
390
|
+
- Generally: you can access the named class from the instance calling the getter `base`.
|
391
|
+
- In particular: If you need the `name`, you can use `base`.`name`.
|
392
|
+
|
393
|
+
**Deprecated**
|
394
|
+
|
395
|
+
```ruby
|
396
|
+
payload[:endpoint].options[:for].name
|
397
|
+
```
|
398
|
+
|
399
|
+
**New**
|
400
|
+
|
401
|
+
```ruby
|
402
|
+
payload[:endpoint].options[:for].base.name
|
403
|
+
```
|
404
|
+
|
405
|
+
#### Changes in rescue_from returned object
|
406
|
+
|
407
|
+
Grape will now check the object returned from `rescue_from` and ensure that it is a `Rack::Response`. That makes sure response is valid and avoids exposing service information. Change any code that invoked `Rack::Response.new(...).finish` in a custom `rescue_from` block to `Rack::Response.new(...)` to comply with the validation.
|
408
|
+
|
409
|
+
```ruby
|
410
|
+
class Twitter::API < Grape::API
|
411
|
+
rescue_from :all do |e|
|
412
|
+
# version prior to 1.2.0
|
413
|
+
Rack::Response.new([ e.message ], 500, { 'Content-type' => 'text/error' }).finish
|
414
|
+
# 1.2.0 version
|
415
|
+
Rack::Response.new([ e.message ], 500, { 'Content-type' => 'text/error' })
|
416
|
+
end
|
417
|
+
end
|
418
|
+
```
|
419
|
+
|
420
|
+
See [#1757](https://github.com/ruby-grape/grape/pull/1757) and [#1776](https://github.com/ruby-grape/grape/pull/1776) for more information.
|
421
|
+
|
4
422
|
### Upgrading to >= 1.1.0
|
5
423
|
|
6
424
|
#### Changes in HTTP Response Code for Unsupported Content Type
|
@@ -70,8 +488,7 @@ See [#1610](https://github.com/ruby-grape/grape/pull/1610) for more information.
|
|
70
488
|
|
71
489
|
#### The `except`, `except_message`, and `proc` options of the `values` validator are deprecated.
|
72
490
|
|
73
|
-
The new `except_values` validator should be used in place of the `except` and `except_message` options of
|
74
|
-
the `values` validator.
|
491
|
+
The new `except_values` validator should be used in place of the `except` and `except_message` options of the `values` validator.
|
75
492
|
|
76
493
|
Arity one Procs may now be used directly as the `values` option to explicitly test param values.
|
77
494
|
|
@@ -147,9 +564,7 @@ get '/example' #=> before: 405, after: 404
|
|
147
564
|
|
148
565
|
#### Removed param processing from built-in OPTIONS handler
|
149
566
|
|
150
|
-
When a request is made to the built-in `OPTIONS` handler, only the `before` and `after`
|
151
|
-
callbacks associated with the resource will be run. The `before_validation` and
|
152
|
-
`after_validation` callbacks and parameter validations will be skipped.
|
567
|
+
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.
|
153
568
|
|
154
569
|
See [#1505](https://github.com/ruby-grape/grape/pull/1505) for more information.
|
155
570
|
|
@@ -170,8 +585,7 @@ See [#1510](https://github.com/ruby-grape/grape/pull/1510) for more information.
|
|
170
585
|
|
171
586
|
#### The default status code for DELETE is now 204 instead of 200.
|
172
587
|
|
173
|
-
Breaking change: Sets the default response status code for a delete request to 204.
|
174
|
-
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.
|
588
|
+
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.
|
175
589
|
|
176
590
|
To achieve the old behavior, one has to set it explicitly:
|
177
591
|
```ruby
|
@@ -349,18 +763,14 @@ See [#1114](https://github.com/ruby-grape/grape/pull/1114) for more information.
|
|
349
763
|
|
350
764
|
#### Bypasses formatters when status code indicates no content
|
351
765
|
|
352
|
-
To be consistent with rack and it's handling of standard responses
|
353
|
-
associated with no content, both default and custom formatters will now
|
766
|
+
To be consistent with rack and it's handling of standard responses associated with no content, both default and custom formatters will now
|
354
767
|
be bypassed when processing responses for status codes defined [by rack](https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L567)
|
355
768
|
|
356
769
|
See [#1190](https://github.com/ruby-grape/grape/pull/1190) for more information.
|
357
770
|
|
358
771
|
#### Redirects respond as plain text with message
|
359
772
|
|
360
|
-
`#redirect` now uses `text/plain` regardless of whether that format has
|
361
|
-
been enabled. This prevents formatters from attempting to serialize the
|
362
|
-
message body and allows for a descriptive message body to be provided - and
|
363
|
-
optionally overridden - that better fulfills the theme of the HTTP spec.
|
773
|
+
`#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.
|
364
774
|
|
365
775
|
See [#1194](https://github.com/ruby-grape/grape/pull/1194) for more information.
|
366
776
|
|
@@ -394,10 +804,7 @@ end
|
|
394
804
|
|
395
805
|
See [#1029](https://github.com/ruby-grape/grape/pull/1029) for more information.
|
396
806
|
|
397
|
-
There is a known issue because of this change. When Grape is used with an older
|
398
|
-
than 1.2.4 version of [warden](https://github.com/hassox/warden) there may be raised
|
399
|
-
the following exception having the [rack-mount](https://github.com/jm/rack-mount) gem's
|
400
|
-
lines as last ones in the backtrace:
|
807
|
+
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:
|
401
808
|
|
402
809
|
```
|
403
810
|
NoMethodError: undefined method `[]' for nil:NilClass
|