grape 1.1.0 → 1.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +370 -44
- data/CONTRIBUTING.md +32 -1
- data/LICENSE +1 -1
- data/README.md +683 -87
- data/UPGRADING.md +481 -17
- data/grape.gemspec +15 -4
- data/lib/grape/api/helpers.rb +2 -0
- data/lib/grape/api/instance.rb +279 -0
- data/lib/grape/api.rb +144 -176
- data/lib/grape/config.rb +34 -0
- data/lib/grape/content_types.rb +34 -0
- data/lib/grape/cookies.rb +4 -0
- data/lib/grape/dry_types.rb +12 -0
- data/lib/grape/dsl/api.rb +1 -1
- data/lib/grape/dsl/callbacks.rb +21 -1
- data/lib/grape/dsl/configuration.rb +1 -1
- data/lib/grape/dsl/desc.rb +41 -23
- data/lib/grape/dsl/headers.rb +7 -2
- data/lib/grape/dsl/helpers.rb +10 -7
- data/lib/grape/dsl/inside_route.rb +118 -62
- data/lib/grape/dsl/logger.rb +2 -0
- data/lib/grape/dsl/middleware.rb +11 -4
- data/lib/grape/dsl/parameters.rb +33 -19
- data/lib/grape/dsl/request_response.rb +12 -9
- data/lib/grape/dsl/routing.rb +22 -13
- data/lib/grape/dsl/settings.rb +10 -6
- data/lib/grape/dsl/validations.rb +19 -14
- data/lib/grape/eager_load.rb +20 -0
- data/lib/grape/endpoint.rb +67 -58
- data/lib/grape/error_formatter/base.rb +2 -0
- data/lib/grape/error_formatter/json.rb +11 -7
- data/lib/grape/error_formatter/txt.rb +2 -0
- data/lib/grape/error_formatter/xml.rb +4 -6
- data/lib/grape/error_formatter.rb +4 -2
- data/lib/grape/exceptions/base.rb +23 -16
- 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 +10 -1
- 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/too_many_multipart_files.rb +11 -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 +10 -1
- data/lib/grape/exceptions/validation.rb +5 -8
- 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/json.rb +3 -0
- data/lib/grape/formatter/serializable_hash.rb +4 -1
- data/lib/grape/formatter/txt.rb +2 -0
- data/lib/grape/formatter/xml.rb +3 -0
- data/lib/grape/formatter.rb +5 -3
- data/lib/grape/http/headers.rb +50 -18
- data/lib/grape/locale/en.yml +11 -8
- data/lib/grape/middleware/auth/base.rb +7 -7
- data/lib/grape/middleware/auth/dsl.rb +9 -2
- 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 +13 -8
- data/lib/grape/middleware/error.rb +22 -17
- data/lib/grape/middleware/filter.rb +2 -0
- data/lib/grape/middleware/formatter.rb +12 -10
- data/lib/grape/middleware/globals.rb +2 -0
- data/lib/grape/middleware/helpers.rb +12 -0
- data/lib/grape/middleware/stack.rb +16 -6
- data/lib/grape/middleware/versioner/accept_version_header.rb +5 -5
- data/lib/grape/middleware/versioner/header.rb +13 -9
- data/lib/grape/middleware/versioner/param.rb +4 -1
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +5 -1
- data/lib/grape/middleware/versioner/path.rb +5 -1
- data/lib/grape/middleware/versioner.rb +2 -0
- data/lib/grape/namespace.rb +14 -2
- data/lib/grape/parser/json.rb +3 -1
- data/lib/grape/parser/xml.rb +3 -1
- data/lib/grape/parser.rb +4 -2
- data/lib/grape/path.rb +16 -3
- data/lib/grape/presenters/presenter.rb +2 -0
- data/lib/grape/request.rb +21 -9
- data/lib/grape/router/attribute_translator.rb +41 -8
- data/lib/grape/router/pattern.rb +21 -17
- data/lib/grape/router/route.rb +15 -29
- data/lib/grape/router.rb +36 -29
- 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/types/invalid_value.rb +8 -0
- 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 +3 -3
- data/lib/grape/util/inheritable_values.rb +7 -25
- data/lib/grape/util/json.rb +4 -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 +99 -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 +3 -1
- data/lib/grape/util/xml.rb +2 -0
- data/lib/grape/validations/attributes_doc.rb +58 -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 +174 -94
- data/lib/grape/validations/single_attribute_iterator.rb +24 -0
- data/lib/grape/validations/types/array_coercer.rb +63 -0
- data/lib/grape/validations/types/build_coercer.rb +47 -49
- data/lib/grape/validations/types/custom_type_coercer.rb +30 -51
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
- data/lib/grape/validations/types/dry_type_coercer.rb +72 -0
- data/lib/grape/validations/types/file.rb +22 -18
- data/lib/grape/validations/types/invalid_value.rb +17 -0
- data/lib/grape/validations/types/json.rb +47 -39
- data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
- data/lib/grape/validations/types/primitive_coercer.rb +75 -0
- data/lib/grape/validations/types/set_coercer.rb +38 -0
- data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
- data/lib/grape/validations/types.rb +106 -63
- data/lib/grape/validations/validator_factory.rb +8 -11
- data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
- data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
- data/lib/grape/validations/validators/as_validator.rb +14 -0
- data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
- data/lib/grape/validations/validators/base.rb +84 -68
- data/lib/grape/validations/validators/coerce_validator.rb +75 -0
- data/lib/grape/validations/validators/default_validator.rb +51 -0
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
- data/lib/grape/validations/validators/except_values_validator.rb +24 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +27 -16
- data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
- data/lib/grape/validations/validators/presence_validator.rb +15 -0
- data/lib/grape/validations/validators/regexp_validator.rb +16 -0
- data/lib/grape/validations/validators/same_as_validator.rb +29 -0
- data/lib/grape/validations/validators/values_validator.rb +88 -0
- data/lib/grape/validations.rb +18 -6
- data/lib/grape/version.rb +3 -1
- data/lib/grape.rb +175 -94
- data/spec/grape/api/custom_validations_spec.rb +117 -44
- data/spec/grape/api/deeply_included_options_spec.rb +4 -4
- data/spec/grape/api/defines_boolean_in_params_spec.rb +38 -0
- data/spec/grape/api/documentation_spec.rb +59 -0
- data/spec/grape/api/inherited_helpers_spec.rb +1 -1
- data/spec/grape/api/instance_spec.rb +103 -0
- data/spec/grape/api/invalid_format_spec.rb +3 -1
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +1 -1
- data/spec/grape/api/nested_helpers_spec.rb +1 -1
- data/spec/grape/api/optional_parameters_in_route_spec.rb +1 -1
- data/spec/grape/api/parameters_modification_spec.rb +2 -2
- data/spec/grape/api/patch_method_helpers_spec.rb +1 -1
- data/spec/grape/api/recognize_path_spec.rb +2 -2
- data/spec/grape/api/required_parameters_in_route_spec.rb +1 -1
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +1 -1
- data/spec/grape/api/routes_with_requirements_spec.rb +59 -0
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +10 -16
- data/spec/grape/api/shared_helpers_spec.rb +1 -1
- data/spec/grape/api_remount_spec.rb +473 -0
- data/spec/grape/api_spec.rb +995 -231
- data/spec/grape/config_spec.rb +17 -0
- data/spec/grape/dsl/callbacks_spec.rb +3 -2
- data/spec/grape/dsl/desc_spec.rb +43 -17
- data/spec/grape/dsl/headers_spec.rb +40 -10
- data/spec/grape/dsl/helpers_spec.rb +6 -5
- data/spec/grape/dsl/inside_route_spec.rb +189 -38
- data/spec/grape/dsl/logger_spec.rb +17 -19
- data/spec/grape/dsl/middleware_spec.rb +11 -2
- data/spec/grape/dsl/parameters_spec.rb +3 -1
- data/spec/grape/dsl/request_response_spec.rb +8 -7
- data/spec/grape/dsl/routing_spec.rb +22 -9
- data/spec/grape/dsl/settings_spec.rb +1 -1
- data/spec/grape/dsl/validations_spec.rb +1 -16
- data/spec/grape/endpoint/declared_spec.rb +846 -0
- data/spec/grape/endpoint_spec.rb +136 -577
- data/spec/grape/entity_spec.rb +31 -24
- data/spec/grape/exceptions/base_spec.rb +81 -0
- data/spec/grape/exceptions/body_parse_errors_spec.rb +4 -1
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +65 -23
- data/spec/grape/exceptions/invalid_formatter_spec.rb +1 -1
- data/spec/grape/exceptions/invalid_response_spec.rb +11 -0
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -2
- data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
- data/spec/grape/exceptions/missing_mime_type_spec.rb +1 -1
- data/spec/grape/exceptions/missing_option_spec.rb +2 -2
- data/spec/grape/exceptions/unknown_options_spec.rb +1 -1
- data/spec/grape/exceptions/unknown_validator_spec.rb +1 -1
- data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
- data/spec/grape/exceptions/validation_errors_spec.rb +21 -15
- data/spec/grape/exceptions/validation_spec.rb +6 -4
- data/spec/grape/extensions/param_builders/hash_spec.rb +8 -8
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +9 -9
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +9 -9
- data/spec/grape/integration/global_namespace_function_spec.rb +2 -2
- data/spec/grape/integration/rack_sendfile_spec.rb +14 -10
- data/spec/grape/integration/rack_spec.rb +25 -8
- data/spec/grape/loading_spec.rb +9 -9
- data/spec/grape/middleware/auth/base_spec.rb +2 -1
- data/spec/grape/middleware/auth/dsl_spec.rb +19 -10
- data/spec/grape/middleware/auth/strategies_spec.rb +62 -22
- data/spec/grape/middleware/base_spec.rb +36 -17
- data/spec/grape/middleware/error_spec.rb +11 -4
- data/spec/grape/middleware/exception_spec.rb +112 -162
- data/spec/grape/middleware/formatter_spec.rb +65 -29
- data/spec/grape/middleware/globals_spec.rb +8 -5
- data/spec/grape/middleware/stack_spec.rb +25 -13
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -2
- data/spec/grape/middleware/versioner/header_spec.rb +37 -14
- data/spec/grape/middleware/versioner/param_spec.rb +8 -2
- data/spec/grape/middleware/versioner/path_spec.rb +6 -2
- data/spec/grape/middleware/versioner_spec.rb +2 -2
- data/spec/grape/named_api_spec.rb +19 -0
- data/spec/grape/parser_spec.rb +10 -6
- data/spec/grape/path_spec.rb +53 -53
- data/spec/grape/presenters/presenter_spec.rb +8 -7
- data/spec/grape/request_spec.rb +29 -3
- data/spec/grape/util/inheritable_setting_spec.rb +9 -8
- data/spec/grape/util/inheritable_values_spec.rb +5 -3
- data/spec/grape/util/reverse_stackable_values_spec.rb +5 -2
- data/spec/grape/util/stackable_values_spec.rb +10 -7
- data/spec/grape/util/strict_hash_configuration_spec.rb +2 -1
- data/spec/grape/validations/attributes_doc_spec.rb +153 -0
- data/spec/grape/validations/instance_behaivour_spec.rb +13 -14
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +40 -0
- data/spec/grape/validations/params_scope_spec.rb +568 -99
- data/spec/grape/validations/single_attribute_iterator_spec.rb +57 -0
- data/spec/grape/validations/types/array_coercer_spec.rb +33 -0
- data/spec/grape/validations/types/primitive_coercer_spec.rb +150 -0
- data/spec/grape/validations/types/set_coercer_spec.rb +32 -0
- data/spec/grape/validations/types_spec.rb +44 -45
- data/spec/grape/validations/validators/all_or_none_spec.rb +134 -32
- data/spec/grape/validations/validators/allow_blank_spec.rb +137 -141
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +169 -31
- data/spec/grape/validations/validators/coerce_spec.rb +491 -151
- data/spec/grape/validations/validators/default_spec.rb +242 -78
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +198 -40
- data/spec/grape/validations/validators/except_values_spec.rb +6 -5
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +181 -30
- data/spec/grape/validations/validators/presence_spec.rb +45 -2
- data/spec/grape/validations/validators/regexp_spec.rb +27 -33
- data/spec/grape/validations/validators/same_as_spec.rb +57 -0
- data/spec/grape/validations/validators/values_spec.rb +227 -180
- data/spec/grape/validations_spec.rb +502 -72
- data/spec/integration/eager_load/eager_load_spec.rb +15 -0
- data/spec/integration/multi_json/json_spec.rb +2 -2
- data/spec/integration/multi_xml/xml_spec.rb +2 -2
- data/spec/shared/versioning_examples.rb +34 -29
- data/spec/spec_helper.rb +31 -5
- data/spec/support/basic_auth_encode_helpers.rb +3 -1
- data/spec/support/chunks.rb +14 -0
- data/spec/support/content_type_helpers.rb +2 -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 +111 -61
- 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/lib/grape/validations/validators/all_or_none.rb +0 -20
- data/lib/grape/validations/validators/allow_blank.rb +0 -16
- data/lib/grape/validations/validators/as.rb +0 -15
- data/lib/grape/validations/validators/at_least_one_of.rb +0 -20
- data/lib/grape/validations/validators/coerce.rb +0 -74
- data/lib/grape/validations/validators/default.rb +0 -48
- data/lib/grape/validations/validators/exactly_one_of.rb +0 -29
- data/lib/grape/validations/validators/except_values.rb +0 -20
- data/lib/grape/validations/validators/mutual_exclusion.rb +0 -25
- data/lib/grape/validations/validators/presence.rb +0 -10
- data/lib/grape/validations/validators/regexp.rb +0 -11
- data/lib/grape/validations/validators/values.rb +0 -71
- data/pkg/grape-0.17.0.gem +0 -0
- data/pkg/grape-0.19.0.gem +0 -0
- data/spec/grape/dsl/configuration_spec.rb +0 -14
- data/spec/grape/validations/attributes_iterator_spec.rb +0 -4
data/UPGRADING.md
CHANGED
@@ -1,6 +1,481 @@
|
|
1
1
|
Upgrading Grape
|
2
2
|
===============
|
3
3
|
|
4
|
+
### Upgrading to >= 1.7.0
|
5
|
+
|
6
|
+
#### Exceptions renaming
|
7
|
+
|
8
|
+
The following exceptions has been renamed for consistency through exceptions naming :
|
9
|
+
|
10
|
+
* `MissingGroupTypeError` => `MissingGroupType`
|
11
|
+
* `UnsupportedGroupTypeError` => `UnsupportedGroupType`
|
12
|
+
|
13
|
+
See [#2227](https://github.com/ruby-grape/grape/pull/2227) for more information.
|
14
|
+
|
15
|
+
#### Handling Multipart Limit Errors
|
16
|
+
|
17
|
+
Rack supports a configurable limit on the number of files created from multipart parameters (`Rack::Utils.multipart_part_limit`) and raises an error if params are received that create too many files. If you were handling the Rack error directly, Grape now wraps that error in `Grape::Execeptions::TooManyMultipartFiles`. Additionally, Grape will return a 413 status code if the exception goes unhandled.
|
18
|
+
|
19
|
+
### Upgrading to >= 1.6.0
|
20
|
+
|
21
|
+
#### Parameter renaming with :as
|
22
|
+
|
23
|
+
Prior to 1.6.0 the [parameter renaming](https://github.com/ruby-grape/grape#renaming) with `:as` was directly touching the request payload ([`#params`](https://github.com/ruby-grape/grape#parameters)) while duplicating the old and the new key to be both available in the hash. This allowed clients to bypass any validation in case they knew the internal name of the parameter. Unfortunately, in combination with [grape-swagger](https://github.com/ruby-grape/grape-swagger) the internal name (name set with `:as`) of the parameters were documented.
|
24
|
+
|
25
|
+
This behavior was fixed. Parameter renaming is now done when using the [`#declared(params)`](https://github.com/ruby-grape/grape#declared) parameters helper. This stops confusing validation/coercion behavior.
|
26
|
+
|
27
|
+
Here comes an illustration of the old and new behaviour as code:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
# (1) Rename a to b, while client sends +a+
|
31
|
+
optional :a, type: Integer, as: :b
|
32
|
+
params = { a: 1 }
|
33
|
+
declared(params, include_missing: false)
|
34
|
+
# expected => { b: 1 }
|
35
|
+
# actual => { b: 1 }
|
36
|
+
|
37
|
+
# (2) Rename a to b, while client sends +b+
|
38
|
+
optional :a, type: Integer, as: :b, values: [1, 2, 3]
|
39
|
+
params = { b: '5' }
|
40
|
+
declared(params, include_missing: false)
|
41
|
+
# expected => { } (>= 1.6.0)
|
42
|
+
# actual => { b: '5' } (uncasted, unvalidated, <= 1.5.3)
|
43
|
+
```
|
44
|
+
|
45
|
+
Another implication of this change is the dependent parameter resolution. Prior to 1.6.0 the following code produced a `Grape::Exceptions::UnknownParameter` because `:a` was replaced by `:b`:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
params do
|
49
|
+
optional :a, as: :b
|
50
|
+
given :a do # (<= 1.5.3 you had to reference +:b+ here to make it work)
|
51
|
+
requires :c
|
52
|
+
end
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
This code now works without any errors, as the renaming is just an internal behaviour of the `#declared(params)` parameter helper.
|
57
|
+
|
58
|
+
See [#2189](https://github.com/ruby-grape/grape/pull/2189) for more information.
|
59
|
+
|
60
|
+
### Upgrading to >= 1.5.3
|
61
|
+
|
62
|
+
#### Nil value and coercion
|
63
|
+
|
64
|
+
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.
|
65
|
+
This behavior was not tested or documented. Version 1.3.0 quietly changed this behavior, in that `nil` values skipped the coercion. Version 1.5.3 fixes and documents this as follows:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
class Api < Grape::API
|
69
|
+
params do
|
70
|
+
optional :value, type: Integer, coerce_with: ->(val) { val || 0 }
|
71
|
+
end
|
72
|
+
|
73
|
+
get 'example' do
|
74
|
+
params[:my_param]
|
75
|
+
end
|
76
|
+
get '/example', params: { value: nil }
|
77
|
+
# 1.5.2 = nil
|
78
|
+
# 1.5.3 = 0
|
79
|
+
get '/example', params: {}
|
80
|
+
# 1.5.2 = nil
|
81
|
+
# 1.5.3 = nil
|
82
|
+
end
|
83
|
+
```
|
84
|
+
See [#2164](https://github.com/ruby-grape/grape/pull/2164) for more information.
|
85
|
+
|
86
|
+
### Upgrading to >= 1.5.1
|
87
|
+
|
88
|
+
#### Dependent params
|
89
|
+
|
90
|
+
If you use [dependent params](https://github.com/ruby-grape/grape#dependent-parameters) with
|
91
|
+
`Grape::Extensions::Hash::ParamBuilder`, make sure a parameter to be dependent on is set as a Symbol.
|
92
|
+
If a String is given, a parameter that other parameters depend on won't be found even if it is present.
|
93
|
+
|
94
|
+
_Correct_:
|
95
|
+
```ruby
|
96
|
+
given :matrix do
|
97
|
+
# dependent params
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
101
|
+
_Wrong_:
|
102
|
+
```ruby
|
103
|
+
given 'matrix' do
|
104
|
+
# dependent params
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
### Upgrading to >= 1.5.0
|
109
|
+
|
110
|
+
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 `{}`.
|
111
|
+
|
112
|
+
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.
|
113
|
+
|
114
|
+
The following rules now apply to the `declared` helper when params are missing and `include_missing=true`:
|
115
|
+
|
116
|
+
* Hash params with children will resolve to a Hash with keys for each declared child.
|
117
|
+
* Hash params with no children will resolve to `{}`.
|
118
|
+
* Set params will resolve to `Set.new`.
|
119
|
+
* Array params will resolve to `[]`.
|
120
|
+
* All other params will resolve to `nil`.
|
121
|
+
|
122
|
+
#### Example
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
class Api < Grape::API
|
126
|
+
params do
|
127
|
+
optional :outer, type: Hash do
|
128
|
+
optional :inner, type: Hash do
|
129
|
+
optional :value, type: String
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
get 'example' do
|
134
|
+
declared(params, include_missing: true)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
```
|
140
|
+
get '/example'
|
141
|
+
# 1.3.3 = {}
|
142
|
+
# 1.5.0 = {outer: {inner: {value:null}}}
|
143
|
+
```
|
144
|
+
|
145
|
+
For more information see [#2103](https://github.com/ruby-grape/grape/pull/2103).
|
146
|
+
|
147
|
+
### Upgrading to >= 1.4.0
|
148
|
+
|
149
|
+
#### Reworking stream and file and un-deprecating stream like-objects
|
150
|
+
|
151
|
+
Previously in 0.16 stream-like objects were deprecated. This release restores their functionality for use-cases other than file streaming.
|
152
|
+
|
153
|
+
This release deprecated `file` in favor of `sendfile` to better document its purpose.
|
154
|
+
|
155
|
+
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).
|
156
|
+
```ruby
|
157
|
+
class API < Grape::API
|
158
|
+
get '/' do
|
159
|
+
sendfile '/path/to/file'
|
160
|
+
end
|
161
|
+
end
|
162
|
+
```
|
163
|
+
|
164
|
+
Use `stream` to stream file content in chunks.
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
class API < Grape::API
|
168
|
+
get '/' do
|
169
|
+
stream '/path/to/file'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
```
|
173
|
+
|
174
|
+
Or use `stream` to stream other kinds of content. In the following example a streamer class
|
175
|
+
streams paginated data from a database.
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
class MyObject
|
179
|
+
attr_accessor :result
|
180
|
+
|
181
|
+
def initialize(query)
|
182
|
+
@result = query
|
183
|
+
end
|
184
|
+
|
185
|
+
def each
|
186
|
+
yield '['
|
187
|
+
# Do paginated DB fetches and return each page formatted
|
188
|
+
first = false
|
189
|
+
result.find_in_batches do |records|
|
190
|
+
yield process_records(records, first)
|
191
|
+
first = false
|
192
|
+
end
|
193
|
+
yield ']'
|
194
|
+
end
|
195
|
+
|
196
|
+
def process_records(records, first)
|
197
|
+
buffer = +''
|
198
|
+
buffer << ',' unless first
|
199
|
+
buffer << records.map(&:to_json).join(',')
|
200
|
+
buffer
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
class API < Grape::API
|
205
|
+
get '/' do
|
206
|
+
stream MyObject.new(Sprocket.all)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
### Upgrading to >= 1.3.3
|
212
|
+
|
213
|
+
#### Nil values for structures
|
214
|
+
|
215
|
+
Nil values have always been a special case when dealing with types, especially with the following structures:
|
216
|
+
|
217
|
+
- Array
|
218
|
+
- Hash
|
219
|
+
- Set
|
220
|
+
|
221
|
+
The behavior for these structures has changed throughout the latest releases. For example:
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
class Api < Grape::API
|
225
|
+
params do
|
226
|
+
require :my_param, type: Array[Integer]
|
227
|
+
end
|
228
|
+
|
229
|
+
get 'example' do
|
230
|
+
params[:my_param]
|
231
|
+
end
|
232
|
+
get '/example', params: { my_param: nil }
|
233
|
+
# 1.3.1 = []
|
234
|
+
# 1.3.2 = nil
|
235
|
+
end
|
236
|
+
```
|
237
|
+
|
238
|
+
For now on, `nil` values stay `nil` values for all types, including arrays, sets and hashes.
|
239
|
+
|
240
|
+
If you want to have the same behavior as 1.3.1, apply a `default` validator:
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
class Api < Grape::API
|
244
|
+
params do
|
245
|
+
require :my_param, type: Array[Integer], default: []
|
246
|
+
end
|
247
|
+
|
248
|
+
get 'example' do
|
249
|
+
params[:my_param]
|
250
|
+
end
|
251
|
+
get '/example', params: { my_param: nil } # => []
|
252
|
+
end
|
253
|
+
```
|
254
|
+
|
255
|
+
#### Default validator
|
256
|
+
|
257
|
+
Default validator is now applied for `nil` values.
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
class Api < Grape::API
|
261
|
+
params do
|
262
|
+
requires :my_param, type: Integer, default: 0
|
263
|
+
end
|
264
|
+
|
265
|
+
get 'example' do
|
266
|
+
params[:my_param]
|
267
|
+
end
|
268
|
+
get '/example', params: { my_param: nil } #=> before: nil, after: 0
|
269
|
+
end
|
270
|
+
```
|
271
|
+
|
272
|
+
### Upgrading to >= 1.3.0
|
273
|
+
|
274
|
+
You will need to upgrade to this version if you depend on `rack >= 2.1.0`.
|
275
|
+
|
276
|
+
#### Ruby
|
277
|
+
|
278
|
+
After adding dry-types, Ruby 2.4 or newer is required.
|
279
|
+
|
280
|
+
#### Coercion
|
281
|
+
|
282
|
+
[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`.
|
283
|
+
|
284
|
+
Here's an example of how to migrate a custom type from Virtus to dry-types:
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
# Legacy Grape parser
|
288
|
+
class SecureUriType < Virtus::Attribute
|
289
|
+
def coerce(input)
|
290
|
+
URI.parse value
|
291
|
+
end
|
292
|
+
|
293
|
+
def value_coerced?(input)
|
294
|
+
value.is_a? String
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
params do
|
299
|
+
requires :secure_uri, type: SecureUri
|
300
|
+
end
|
301
|
+
```
|
302
|
+
|
303
|
+
To use dry-types, we need to:
|
304
|
+
|
305
|
+
1. Remove the inheritance of `Virtus::Attribute`
|
306
|
+
1. Rename `coerce` to `self.parse`
|
307
|
+
1. Rename `value_coerced?` to `self.parsed?`
|
308
|
+
|
309
|
+
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:
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
# New dry-types parser
|
313
|
+
class SecureUri
|
314
|
+
def self.parse(value)
|
315
|
+
URI.parse value
|
316
|
+
end
|
317
|
+
|
318
|
+
def self.parsed?(value)
|
319
|
+
value.is_a? URI::HTTPS
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
params do
|
324
|
+
requires :secure_uri, type: SecureUri
|
325
|
+
end
|
326
|
+
```
|
327
|
+
|
328
|
+
#### Coercing to `FalseClass` or `TrueClass` no longer works
|
329
|
+
|
330
|
+
Previous Grape versions allowed this, though it wasn't documented:
|
331
|
+
|
332
|
+
```ruby
|
333
|
+
requires :true_value, type: TrueClass
|
334
|
+
requires :bool_value, types: [FalseClass, TrueClass]
|
335
|
+
```
|
336
|
+
|
337
|
+
This is no longer supported, if you do this, your values will never be valid. Instead you should do this:
|
338
|
+
|
339
|
+
```ruby
|
340
|
+
requires :true_value, type: Boolean # in your endpoint you should validate if this is actually `true`
|
341
|
+
requires :bool_value, type: Boolean
|
342
|
+
```
|
343
|
+
|
344
|
+
#### Ensure that Array types have explicit coercions
|
345
|
+
|
346
|
+
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:
|
347
|
+
|
348
|
+
```ruby
|
349
|
+
requires :values, type: Array[String]
|
350
|
+
```
|
351
|
+
|
352
|
+
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:
|
353
|
+
|
354
|
+
```ruby
|
355
|
+
requires :values, type: Array[String], coerce_with: ->(val) { val.split(',').map(&:strip) }
|
356
|
+
```
|
357
|
+
|
358
|
+
Likewise, for `Array[Integer]`, you might do:
|
359
|
+
|
360
|
+
```ruby
|
361
|
+
requires :values, type: Array[Integer], coerce_with: ->(val) { val.split(',').map(&:strip).map(&:to_i) }
|
362
|
+
```
|
363
|
+
|
364
|
+
For more information see [#1920](https://github.com/ruby-grape/grape/pull/1920).
|
365
|
+
|
366
|
+
### Upgrading to >= 1.2.4
|
367
|
+
|
368
|
+
#### Headers in `error!` call
|
369
|
+
|
370
|
+
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.
|
371
|
+
|
372
|
+
```ruby
|
373
|
+
class SampleApi < Grape::API
|
374
|
+
before do
|
375
|
+
header 'X-Before-Header', 'before_call'
|
376
|
+
end
|
377
|
+
|
378
|
+
get 'ping' do
|
379
|
+
header 'X-App-Header', 'on_call'
|
380
|
+
error! :pong, 400, 'X-Error-Details' => 'Invalid token'
|
381
|
+
end
|
382
|
+
end
|
383
|
+
```
|
384
|
+
**Former behaviour**
|
385
|
+
```ruby
|
386
|
+
response.headers['X-Before-Header'] # => nil
|
387
|
+
response.headers['X-App-Header'] # => nil
|
388
|
+
response.headers['X-Error-Details'] # => Invalid token
|
389
|
+
```
|
390
|
+
|
391
|
+
**Current behaviour**
|
392
|
+
```ruby
|
393
|
+
response.headers['X-Before-Header'] # => 'before_call'
|
394
|
+
response.headers['X-App-Header'] # => 'on_call'
|
395
|
+
response.headers['X-Error-Details'] # => Invalid token
|
396
|
+
```
|
397
|
+
|
398
|
+
### Upgrading to >= 1.2.1
|
399
|
+
|
400
|
+
#### Obtaining the name of a mounted class
|
401
|
+
|
402
|
+
In order to make obtaining the name of a mounted class simpler, we've delegated `.to_s` to `base.name`
|
403
|
+
|
404
|
+
**Deprecated in 1.2.0**
|
405
|
+
```ruby
|
406
|
+
payload[:endpoint].options[:for].name
|
407
|
+
```
|
408
|
+
**New**
|
409
|
+
```ruby
|
410
|
+
payload[:endpoint].options[:for].to_s
|
411
|
+
```
|
412
|
+
|
413
|
+
### Upgrading to >= 1.2.0
|
414
|
+
|
415
|
+
#### Changes in the Grape::API class
|
416
|
+
|
417
|
+
##### Patching the class
|
418
|
+
|
419
|
+
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`.
|
420
|
+
|
421
|
+
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`.
|
422
|
+
|
423
|
+
Note, this is particularly relevant if you are opening the class `Grape::API` for modification.
|
424
|
+
|
425
|
+
**Deprecated**
|
426
|
+
```ruby
|
427
|
+
class Grape::API
|
428
|
+
# your patched logic
|
429
|
+
...
|
430
|
+
end
|
431
|
+
```
|
432
|
+
**New**
|
433
|
+
```ruby
|
434
|
+
class Grape::API::Instance
|
435
|
+
# your patched logic
|
436
|
+
...
|
437
|
+
end
|
438
|
+
```
|
439
|
+
|
440
|
+
##### `name` (and other caveats) of the mounted API
|
441
|
+
|
442
|
+
After the patch, the mounted API is no longer a Named class inheriting from `Grape::API`, it is an anonymous class
|
443
|
+
which inherit from `Grape::API::Instance`.
|
444
|
+
|
445
|
+
What this means in practice, is:
|
446
|
+
|
447
|
+
- Generally: you can access the named class from the instance calling the getter `base`.
|
448
|
+
- In particular: If you need the `name`, you can use `base`.`name`.
|
449
|
+
|
450
|
+
**Deprecated**
|
451
|
+
|
452
|
+
```ruby
|
453
|
+
payload[:endpoint].options[:for].name
|
454
|
+
```
|
455
|
+
|
456
|
+
**New**
|
457
|
+
|
458
|
+
```ruby
|
459
|
+
payload[:endpoint].options[:for].base.name
|
460
|
+
```
|
461
|
+
|
462
|
+
#### Changes in rescue_from returned object
|
463
|
+
|
464
|
+
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.
|
465
|
+
|
466
|
+
```ruby
|
467
|
+
class Twitter::API < Grape::API
|
468
|
+
rescue_from :all do |e|
|
469
|
+
# version prior to 1.2.0
|
470
|
+
Rack::Response.new([ e.message ], 500, { 'Content-type' => 'text/error' }).finish
|
471
|
+
# 1.2.0 version
|
472
|
+
Rack::Response.new([ e.message ], 500, { 'Content-type' => 'text/error' })
|
473
|
+
end
|
474
|
+
end
|
475
|
+
```
|
476
|
+
|
477
|
+
See [#1757](https://github.com/ruby-grape/grape/pull/1757) and [#1776](https://github.com/ruby-grape/grape/pull/1776) for more information.
|
478
|
+
|
4
479
|
### Upgrading to >= 1.1.0
|
5
480
|
|
6
481
|
#### Changes in HTTP Response Code for Unsupported Content Type
|
@@ -70,8 +545,7 @@ See [#1610](https://github.com/ruby-grape/grape/pull/1610) for more information.
|
|
70
545
|
|
71
546
|
#### The `except`, `except_message`, and `proc` options of the `values` validator are deprecated.
|
72
547
|
|
73
|
-
The new `except_values` validator should be used in place of the `except` and `except_message` options of
|
74
|
-
the `values` validator.
|
548
|
+
The new `except_values` validator should be used in place of the `except` and `except_message` options of the `values` validator.
|
75
549
|
|
76
550
|
Arity one Procs may now be used directly as the `values` option to explicitly test param values.
|
77
551
|
|
@@ -147,9 +621,7 @@ get '/example' #=> before: 405, after: 404
|
|
147
621
|
|
148
622
|
#### Removed param processing from built-in OPTIONS handler
|
149
623
|
|
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.
|
624
|
+
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
625
|
|
154
626
|
See [#1505](https://github.com/ruby-grape/grape/pull/1505) for more information.
|
155
627
|
|
@@ -170,8 +642,7 @@ See [#1510](https://github.com/ruby-grape/grape/pull/1510) for more information.
|
|
170
642
|
|
171
643
|
#### The default status code for DELETE is now 204 instead of 200.
|
172
644
|
|
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.
|
645
|
+
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
646
|
|
176
647
|
To achieve the old behavior, one has to set it explicitly:
|
177
648
|
```ruby
|
@@ -349,18 +820,14 @@ See [#1114](https://github.com/ruby-grape/grape/pull/1114) for more information.
|
|
349
820
|
|
350
821
|
#### Bypasses formatters when status code indicates no content
|
351
822
|
|
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
|
823
|
+
To be consistent with rack and it's handling of standard responses associated with no content, both default and custom formatters will now
|
354
824
|
be bypassed when processing responses for status codes defined [by rack](https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L567)
|
355
825
|
|
356
826
|
See [#1190](https://github.com/ruby-grape/grape/pull/1190) for more information.
|
357
827
|
|
358
828
|
#### Redirects respond as plain text with message
|
359
829
|
|
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.
|
830
|
+
`#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
831
|
|
365
832
|
See [#1194](https://github.com/ruby-grape/grape/pull/1194) for more information.
|
366
833
|
|
@@ -394,10 +861,7 @@ end
|
|
394
861
|
|
395
862
|
See [#1029](https://github.com/ruby-grape/grape/pull/1029) for more information.
|
396
863
|
|
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:
|
864
|
+
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
865
|
|
402
866
|
```
|
403
867
|
NoMethodError: undefined method `[]' for nil:NilClass
|
data/grape.gemspec
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path('lib', __dir__)
|
2
4
|
require 'grape/version'
|
3
5
|
|
4
6
|
Gem::Specification.new do |s|
|
@@ -11,15 +13,24 @@ Gem::Specification.new do |s|
|
|
11
13
|
s.summary = 'A simple Ruby framework for building REST-like APIs.'
|
12
14
|
s.description = 'A Ruby framework for rapid API development with great conventions.'
|
13
15
|
s.license = 'MIT'
|
16
|
+
s.metadata = {
|
17
|
+
'bug_tracker_uri' => 'https://github.com/ruby-grape/grape/issues',
|
18
|
+
'changelog_uri' => "https://github.com/ruby-grape/grape/blob/v#{s.version}/CHANGELOG.md",
|
19
|
+
'documentation_uri' => "https://www.rubydoc.info/gems/grape/#{s.version}",
|
20
|
+
'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}"
|
21
|
+
}
|
14
22
|
|
15
23
|
s.add_runtime_dependency 'activesupport'
|
16
24
|
s.add_runtime_dependency 'builder'
|
25
|
+
s.add_runtime_dependency 'dry-types', '>= 1.1'
|
17
26
|
s.add_runtime_dependency 'mustermann-grape', '~> 1.0.0'
|
18
|
-
s.add_runtime_dependency 'rack', '>= 1.3.0'
|
27
|
+
s.add_runtime_dependency 'rack', '>= 1.3.0', '< 3'
|
19
28
|
s.add_runtime_dependency 'rack-accept'
|
20
|
-
s.add_runtime_dependency 'virtus', '>= 1.0.0'
|
21
29
|
|
22
|
-
s.files =
|
30
|
+
s.files = %w[CHANGELOG.md CONTRIBUTING.md README.md grape.png UPGRADING.md LICENSE]
|
31
|
+
s.files += %w[grape.gemspec]
|
32
|
+
s.files += Dir['lib/**/*']
|
23
33
|
s.test_files = Dir['spec/**/*']
|
24
34
|
s.require_paths = ['lib']
|
35
|
+
s.required_ruby_version = '>= 2.6.0'
|
25
36
|
end
|