grape 2.1.3 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +45 -0
- data/README.md +9 -7
- data/UPGRADING.md +27 -0
- data/grape.gemspec +7 -6
- data/lib/grape/api/instance.rb +22 -58
- data/lib/grape/api.rb +2 -11
- data/lib/grape/content_types.rb +13 -8
- data/lib/grape/dsl/desc.rb +27 -24
- data/lib/grape/dsl/helpers.rb +7 -3
- data/lib/grape/dsl/inside_route.rb +18 -24
- data/lib/grape/dsl/parameters.rb +2 -2
- data/lib/grape/dsl/request_response.rb +14 -18
- data/lib/grape/dsl/routing.rb +5 -12
- data/lib/grape/endpoint.rb +90 -82
- data/lib/grape/error_formatter/base.rb +51 -21
- data/lib/grape/error_formatter/json.rb +7 -15
- data/lib/grape/error_formatter/jsonapi.rb +7 -0
- data/lib/grape/error_formatter/serializable_hash.rb +7 -0
- data/lib/grape/error_formatter/txt.rb +13 -20
- data/lib/grape/error_formatter/xml.rb +3 -13
- data/lib/grape/error_formatter.rb +5 -25
- data/lib/grape/exceptions/base.rb +18 -30
- data/lib/grape/exceptions/validation.rb +5 -4
- data/lib/grape/exceptions/validation_errors.rb +2 -2
- data/lib/grape/formatter/base.rb +16 -0
- data/lib/grape/formatter/json.rb +4 -6
- data/lib/grape/formatter/serializable_hash.rb +1 -1
- data/lib/grape/formatter/txt.rb +3 -5
- data/lib/grape/formatter/xml.rb +4 -6
- data/lib/grape/formatter.rb +7 -25
- data/lib/grape/http/headers.rb +1 -0
- data/lib/grape/locale/en.yml +1 -0
- data/lib/grape/middleware/base.rb +14 -13
- data/lib/grape/middleware/error.rb +13 -9
- data/lib/grape/middleware/formatter.rb +3 -3
- data/lib/grape/middleware/versioner/accept_version_header.rb +7 -30
- data/lib/grape/middleware/versioner/base.rb +82 -0
- data/lib/grape/middleware/versioner/header.rb +89 -10
- data/lib/grape/middleware/versioner/param.rb +4 -22
- data/lib/grape/middleware/versioner/path.rb +10 -32
- data/lib/grape/middleware/versioner.rb +7 -14
- data/lib/grape/namespace.rb +1 -1
- data/lib/grape/parser/base.rb +16 -0
- data/lib/grape/parser/json.rb +6 -8
- data/lib/grape/parser/jsonapi.rb +7 -0
- data/lib/grape/parser/xml.rb +6 -8
- data/lib/grape/parser.rb +5 -23
- data/lib/grape/path.rb +39 -56
- data/lib/grape/request.rb +2 -2
- data/lib/grape/router/base_route.rb +2 -2
- data/lib/grape/router/greedy_route.rb +2 -2
- data/lib/grape/router/pattern.rb +23 -18
- data/lib/grape/router/route.rb +13 -5
- data/lib/grape/router.rb +5 -5
- data/lib/grape/util/registry.rb +27 -0
- data/lib/grape/validations/contract_scope.rb +2 -39
- data/lib/grape/validations/params_scope.rb +7 -11
- data/lib/grape/validations/types/dry_type_coercer.rb +10 -6
- data/lib/grape/validations/validator_factory.rb +2 -2
- data/lib/grape/validations/validators/allow_blank_validator.rb +1 -1
- data/lib/grape/validations/validators/base.rb +5 -9
- data/lib/grape/validations/validators/coerce_validator.rb +1 -1
- data/lib/grape/validations/validators/contract_scope_validator.rb +41 -0
- data/lib/grape/validations/validators/default_validator.rb +1 -1
- data/lib/grape/validations/validators/except_values_validator.rb +1 -1
- data/lib/grape/validations/validators/length_validator.rb +11 -4
- data/lib/grape/validations/validators/regexp_validator.rb +1 -1
- data/lib/grape/validations/validators/values_validator.rb +15 -57
- data/lib/grape/validations.rb +8 -17
- data/lib/grape/version.rb +1 -1
- data/lib/grape.rb +1 -1
- metadata +15 -12
- data/lib/grape/util/accept_header_handler.rb +0 -105
- data/lib/grape/util/registrable.rb +0 -15
- data/lib/grape/validations/types/build_coercer.rb +0 -92
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eefbc6eed618a448bcc9657c03ca73f5771f22b5f13b4c56cacb7ec7e05750ac
|
4
|
+
data.tar.gz: 6506e73d4ce49cdf54c142acee7085217bd6f55211f86b74a50d23a83ae48c02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e5dab9502a1484f267e9881b8a368cfe809f47eaf9870d14db2002c63c48863f92bbd561c54dd81b0c4e4ff416a7fa7abc121c0052576dc0d7cb088d425d282
|
7
|
+
data.tar.gz: e78c3fc83ae2a908ef510a387cd31060a13eeb23d7d209c842f2d7e64286ca21e506472fd7ca9f397e1169f7e74fc439a097c376d4ba6682b1c091009fc52acd
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,48 @@
|
|
1
|
+
### 2.3.0 (2025-02-08)
|
2
|
+
|
3
|
+
#### Features
|
4
|
+
|
5
|
+
* [#2497](https://github.com/ruby-grape/grape/pull/2497): Update RuboCop to 1.66.1 - [@ericproulx](https://github.com/ericproulx).
|
6
|
+
* [#2500](https://github.com/ruby-grape/grape/pull/2500): Remove deprecated `file` method - [@ericproulx](https://github.com/ericproulx).
|
7
|
+
* [#2501](https://github.com/ruby-grape/grape/pull/2501): Remove deprecated `except` and `proc` options in values validator - [@ericproulx](https://github.com/ericproulx).
|
8
|
+
* [#2502](https://github.com/ruby-grape/grape/pull/2502): Remove deprecation `options` in `desc` - [@ericproulx](https://github.com/ericproulx).
|
9
|
+
* [#2512](https://github.com/ruby-grape/grape/pull/2512): Optimize hash alloc - [@ericproulx](https://github.com/ericproulx).
|
10
|
+
* [#2513](https://github.com/ruby-grape/grape/pull/2513): Optimize Grape::Path - [@ericproulx](https://github.com/ericproulx).
|
11
|
+
* [#2514](https://github.com/ruby-grape/grape/pull/2514): Add rails 8.0 to CI - [@ericproulx](https://github.com/ericproulx).
|
12
|
+
* [#2516](https://github.com/ruby-grape/grape/pull/2516): Dynamic registration for parsers, formatters, versioners - [@ericproulx](https://github.com/ericproulx).
|
13
|
+
* [#2518](https://github.com/ruby-grape/grape/pull/2518): Add ruby 3.4 to CI - [@ericproulx](https://github.com/ericproulx).
|
14
|
+
|
15
|
+
#### Fixes
|
16
|
+
|
17
|
+
* [#2504](https://github.com/ruby-grape/grape/pull/2504): Fix leaky modules in specs - [@ericproulx](https://github.com/ericproulx).
|
18
|
+
* [#2506](https://github.com/ruby-grape/grape/pull/2506): Fix fetch_formatter api_format - [@ericproulx](https://github.com/ericproulx).
|
19
|
+
* [#2507](https://github.com/ruby-grape/grape/pull/2507): Fix type: Set with values - [@nikolai-b](https://github.com/nikolai-b).
|
20
|
+
* [#2510](https://github.com/ruby-grape/grape/pull/2510): Fix ContractScope's validator inheritance - [@ericproulx](https://github.com/ericproulx).
|
21
|
+
* [#2521](https://github.com/ruby-grape/grape/pull/2521): Fixed typo in README - [@datpmt](https://github.com/datpmt).
|
22
|
+
* [#2525](https://github.com/ruby-grape/grape/pull/2525): Require logger before active_support - [@ericproulx](https://github.com/ericproulx).
|
23
|
+
* [#2524](https://github.com/ruby-grape/grape/pull/2524): Fix validators bad encoding - [@ericproulx](https://github.com/ericproulx).
|
24
|
+
* [#2530](https://github.com/ruby-grape/grape/pull/2530): Fix endpoint's status when rescue_from without a block - [@ericproulx](https://github.com/ericproulx).
|
25
|
+
* [#2529](https://github.com/ruby-grape/grape/pull/2529): Fix missing settings on mounted routes (when settings are identical) - [@Haerezis](https://github.com/Haerezis).
|
26
|
+
|
27
|
+
### 2.2.0 (2024-09-14)
|
28
|
+
|
29
|
+
#### Features
|
30
|
+
|
31
|
+
* [#2475](https://github.com/ruby-grape/grape/pull/2475): Remove Grape::Util::Registrable - [@ericproulx](https://github.com/ericproulx).
|
32
|
+
* [#2484](https://github.com/ruby-grape/grape/pull/2484): Refactor versioner middlewares - [@ericproulx](https://github.com/ericproulx).
|
33
|
+
* [#2489](https://github.com/ruby-grape/grape/pull/2489): Add Rails 7.2 in CI workflow - [@ericproulx](https://github.com/ericproulx).
|
34
|
+
* [#2493](https://github.com/ruby-grape/grape/pull/2493): MFA required when releasing - [@ericproulx](https://github.com/ericproulx).
|
35
|
+
|
36
|
+
#### Fixes
|
37
|
+
|
38
|
+
* [#2471](https://github.com/ruby-grape/grape/pull/2471): Fix absence of original_exception and/or backtrace even if passed in error! - [@numbata](https://github.com/numbata).
|
39
|
+
* [#2478](https://github.com/ruby-grape/grape/pull/2478): Fix rescue_from with invalid response - [@ericproulx](https://github.com/ericproulx).
|
40
|
+
* [#2480](https://github.com/ruby-grape/grape/pull/2480): Fix rescue_from ValidationErrors exception - [@numbata](https://github.com/numbata).
|
41
|
+
* [#2464](https://github.com/ruby-grape/grape/pull/2464): The `length` validator only takes effect for parameters with types that support `#length` method - [@OuYangJinTing](https://github.com/OuYangJinTing).
|
42
|
+
* [#2485](https://github.com/ruby-grape/grape/pull/2485): Add `is:` param to length validator - [@dakad](https://github.com/dakad).
|
43
|
+
* [#2492](https://github.com/ruby-grape/grape/pull/2492): Fix `Grape::Endpoint#inspect` method - [@ericproulx](https://github.com/ericproulx).
|
44
|
+
* [#2496](https://github.com/ruby-grape/grape/pull/2496): Reduce object allocation when compiling - [@ericproulx](https://github.com/ericproulx).
|
45
|
+
|
1
46
|
### 2.1.3 (2024-07-13)
|
2
47
|
|
3
48
|
#### Fixes
|
data/README.md
CHANGED
@@ -157,7 +157,7 @@ Grape is a REST-like API framework for Ruby. It's designed to run on Rack or com
|
|
157
157
|
|
158
158
|
## Stable Release
|
159
159
|
|
160
|
-
You're reading the documentation for the
|
160
|
+
You're reading the documentation for the next release of Grape, 2.3.0.
|
161
161
|
Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
|
162
162
|
|
163
163
|
## Project Resources
|
@@ -1713,10 +1713,11 @@ end
|
|
1713
1713
|
|
1714
1714
|
Parameters with types that support `#length` method can be restricted to have a specific length with the `:length` option.
|
1715
1715
|
|
1716
|
-
The validator accepts `:min` or `:max` or both options to validate that the value of the parameter is within the given limits.
|
1716
|
+
The validator accepts `:min` or `:max` or both options or only `:is` to validate that the value of the parameter is within the given limits.
|
1717
1717
|
|
1718
1718
|
```ruby
|
1719
1719
|
params do
|
1720
|
+
requires :code, type: String, length: { is: 2 }
|
1720
1721
|
requires :str, type: String, length: { min: 3 }
|
1721
1722
|
requires :list, type: [Integer], length: { min: 3, max: 5 }
|
1722
1723
|
requires :hash, type: Hash, length: { max: 5 }
|
@@ -2044,7 +2045,8 @@ end
|
|
2044
2045
|
|
2045
2046
|
```ruby
|
2046
2047
|
params do
|
2047
|
-
requires :
|
2048
|
+
requires :code, type: String, length: { is: 2, message: 'code is expected to be exactly 2 characters long' }
|
2049
|
+
requires :str, type: String, length: { min: 5, message: 'str is expected to be at least 5 characters long' }
|
2048
2050
|
requires :list, type: [Integer], length: { min: 2, max: 3, message: 'list is expected to have between 2 and 3 elements' }
|
2049
2051
|
end
|
2050
2052
|
```
|
@@ -3064,7 +3066,7 @@ end
|
|
3064
3066
|
* `GET /hello.xls` with an `Accept: application/xml` header has an unrecognized extension, but the `Accept` header corresponds to a recognized format, so it will respond with XML.
|
3065
3067
|
* `GET /hello.xls` with an `Accept: text/plain` header has an unrecognized extension *and* an unrecognized `Accept` header, so it will respond with JSON (the default format).
|
3066
3068
|
|
3067
|
-
You can override this process explicitly by
|
3069
|
+
You can override this process explicitly by calling `api_format` in the API itself.
|
3068
3070
|
For example, the following API will let you upload arbitrary files and return their contents as an attachment with the correct MIME type.
|
3069
3071
|
|
3070
3072
|
```ruby
|
@@ -3072,7 +3074,7 @@ class Twitter::API < Grape::API
|
|
3072
3074
|
post 'attachment' do
|
3073
3075
|
filename = params[:file][:filename]
|
3074
3076
|
content_type MIME::Types.type_for(filename)[0].to_s
|
3075
|
-
|
3077
|
+
api_format :binary # there's no formatter for :binary, data will be returned "as is"
|
3076
3078
|
header 'Content-Disposition', "attachment; filename*=UTF-8''#{CGI.escape(filename)}"
|
3077
3079
|
params[:file][:tempfile].read
|
3078
3080
|
end
|
@@ -3534,8 +3536,8 @@ Please use `Route#xyz` instead.
|
|
3534
3536
|
|
3535
3537
|
Note that difference of `Route#options` and `Route#settings`.
|
3536
3538
|
|
3537
|
-
The `options` can be referred from your route, it should be set by
|
3538
|
-
The `settings` can also be referred from your route, but it should be set by
|
3539
|
+
The `options` can be referred from your route, it should be set by specifying key and value on verb methods such as `get`, `post` and `put`.
|
3540
|
+
The `settings` can also be referred from your route, but it should be set by specifying key and value on `route_setting`.
|
3539
3541
|
|
3540
3542
|
## Current Route and Endpoint
|
3541
3543
|
|
data/UPGRADING.md
CHANGED
@@ -1,6 +1,33 @@
|
|
1
1
|
Upgrading Grape
|
2
2
|
===============
|
3
3
|
|
4
|
+
### Upgrading to >= 2.3.0
|
5
|
+
|
6
|
+
### `content_type` vs `api.format` inside API
|
7
|
+
|
8
|
+
Before 2.3.0, `content_type` had priority over `env['api.format']` when set in an API, which was incorrect. The priority has been flipped and `env['api.format']` will be checked first.
|
9
|
+
In addition, the function `api_format` has been added. Instead of setting `env['api.format']` directly, you can call `api_format`.
|
10
|
+
See [#2506](https://github.com/ruby-grape/grape/pull/2506) for more information.
|
11
|
+
|
12
|
+
#### Remove Deprecated Methods and Options
|
13
|
+
|
14
|
+
- Deprecated `file` method has been removed. Use `send_file` or `stream`.
|
15
|
+
See [#2500](https://github.com/ruby-grape/grape/pull/2500) for more information.
|
16
|
+
|
17
|
+
- The `except` and `proc` options have been removed from the `values` validator. Use `except_values` validator or assign `proc` directly to `values`.
|
18
|
+
See [#2501](https://github.com/ruby-grape/grape/pull/2501) for more information.
|
19
|
+
|
20
|
+
- `Passing an options hash and a block to 'desc'` deprecation has been removed. Move all hash options to block instead.
|
21
|
+
See [#2502](https://github.com/ruby-grape/grape/pull/2502) for more information.
|
22
|
+
|
23
|
+
### Upgrading to >= 2.2.0
|
24
|
+
|
25
|
+
### `Length` validator
|
26
|
+
|
27
|
+
After Grape 2.2.0, `length` validator will only take effect for parameters with types that support `#length` method, will not throw `ArgumentError` exception.
|
28
|
+
|
29
|
+
See [#2464](https://github.com/ruby-grape/grape/pull/2464) for more information.
|
30
|
+
|
4
31
|
### Upgrading to >= 2.1.0
|
5
32
|
|
6
33
|
#### Optional Builder
|
data/grape.gemspec
CHANGED
@@ -17,14 +17,15 @@ Gem::Specification.new do |s|
|
|
17
17
|
'bug_tracker_uri' => 'https://github.com/ruby-grape/grape/issues',
|
18
18
|
'changelog_uri' => "https://github.com/ruby-grape/grape/blob/v#{s.version}/CHANGELOG.md",
|
19
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}"
|
20
|
+
'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}",
|
21
|
+
'rubygems_mfa_required' => 'true'
|
21
22
|
}
|
22
23
|
|
23
|
-
s.
|
24
|
-
s.
|
25
|
-
s.
|
26
|
-
s.
|
27
|
-
s.
|
24
|
+
s.add_dependency 'activesupport', '>= 6'
|
25
|
+
s.add_dependency 'dry-types', '>= 1.1'
|
26
|
+
s.add_dependency 'mustermann-grape', '~> 1.1.0'
|
27
|
+
s.add_dependency 'rack', '>= 2'
|
28
|
+
s.add_dependency 'zeitwerk'
|
28
29
|
|
29
30
|
s.files = Dir['lib/**/*', 'CHANGELOG.md', 'CONTRIBUTING.md', 'README.md', 'grape.png', 'UPGRADING.md', 'LICENSE', 'grape.gemspec']
|
30
31
|
s.require_paths = ['lib']
|
data/lib/grape/api/instance.rb
CHANGED
@@ -194,88 +194,52 @@ module Grape
|
|
194
194
|
# will return an HTTP 405 response for any HTTP method that the resource
|
195
195
|
# cannot handle.
|
196
196
|
def add_head_not_allowed_methods_and_options_methods
|
197
|
-
versioned_route_configs = collect_route_config_per_pattern
|
198
197
|
# The paths we collected are prepared (cf. Path#prepare), so they
|
199
198
|
# contain already versioning information when using path versioning.
|
199
|
+
all_routes = self.class.endpoints.map(&:routes).flatten
|
200
|
+
|
200
201
|
# Disable versioning so adding a route won't prepend versioning
|
201
202
|
# informations again.
|
202
|
-
|
203
|
-
without_versioning do
|
204
|
-
versioned_route_configs.each do |config|
|
205
|
-
next if config[:options][:matching_wildchar]
|
206
|
-
|
207
|
-
allowed_methods = config[:methods].dup
|
208
|
-
|
209
|
-
allowed_methods |= [Rack::HEAD] if !self.class.namespace_inheritable(:do_not_route_head) && allowed_methods.include?(Rack::GET)
|
210
|
-
|
211
|
-
allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Rack::OPTIONS] | allowed_methods)
|
212
|
-
|
213
|
-
config[:endpoint].options[:options_route_enabled] = true unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Rack::OPTIONS)
|
214
|
-
|
215
|
-
attributes = config.merge(allowed_methods: allowed_methods, allow_header: allow_header)
|
216
|
-
generate_not_allowed_method(config[:pattern], **attributes)
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
203
|
+
without_root_prefix_and_versioning { collect_route_config_per_pattern(all_routes) }
|
220
204
|
end
|
221
205
|
|
222
|
-
def collect_route_config_per_pattern
|
223
|
-
all_routes = self.class.endpoints.map(&:routes).flatten
|
206
|
+
def collect_route_config_per_pattern(all_routes)
|
224
207
|
routes_by_regexp = all_routes.group_by(&:pattern_regexp)
|
225
208
|
|
226
209
|
# Build the configuration based on the first endpoint and the collection of methods supported.
|
227
|
-
routes_by_regexp.
|
228
|
-
last_route
|
229
|
-
|
230
|
-
{
|
231
|
-
options: { matching_wildchar: matching_wildchar },
|
232
|
-
pattern: last_route.pattern,
|
233
|
-
requirements: last_route.requirements,
|
234
|
-
path: last_route.origin,
|
235
|
-
endpoint: last_route.app,
|
236
|
-
methods: matching_wildchar ? Grape::Http::Headers::SUPPORTED_METHODS : routes.map(&:request_method)
|
237
|
-
}
|
238
|
-
end
|
239
|
-
end
|
210
|
+
routes_by_regexp.each_value do |routes|
|
211
|
+
last_route = routes.last # Most of the configuration is taken from the last endpoint
|
212
|
+
next if routes.any? { |route| route.request_method == '*' }
|
240
213
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
214
|
+
allowed_methods = routes.map(&:request_method)
|
215
|
+
allowed_methods |= [Rack::HEAD] if !self.class.namespace_inheritable(:do_not_route_head) && allowed_methods.include?(Rack::GET)
|
216
|
+
|
217
|
+
allow_header = self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Rack::OPTIONS] | allowed_methods
|
218
|
+
last_route.app.options[:options_route_enabled] = true unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Rack::OPTIONS)
|
219
|
+
|
220
|
+
@router.associate_routes(last_route.pattern, {
|
221
|
+
endpoint: last_route.app,
|
222
|
+
allow_header: allow_header
|
223
|
+
})
|
224
|
+
end
|
252
225
|
end
|
253
226
|
|
254
227
|
# Allows definition of endpoints that ignore the versioning configuration
|
255
228
|
# used by the rest of your API.
|
256
|
-
def
|
229
|
+
def without_root_prefix_and_versioning
|
257
230
|
old_version = self.class.namespace_inheritable(:version)
|
258
231
|
old_version_options = self.class.namespace_inheritable(:version_options)
|
232
|
+
old_root_prefix = self.class.namespace_inheritable(:root_prefix)
|
259
233
|
|
260
234
|
self.class.namespace_inheritable_to_nil(:version)
|
261
235
|
self.class.namespace_inheritable_to_nil(:version_options)
|
236
|
+
self.class.namespace_inheritable_to_nil(:root_prefix)
|
262
237
|
|
263
238
|
yield
|
264
239
|
|
265
240
|
self.class.namespace_inheritable(:version, old_version)
|
266
241
|
self.class.namespace_inheritable(:version_options, old_version_options)
|
267
|
-
|
268
|
-
|
269
|
-
# Allows definition of endpoints that ignore the root prefix used by the
|
270
|
-
# rest of your API.
|
271
|
-
def without_root_prefix(&_block)
|
272
|
-
old_prefix = self.class.namespace_inheritable(:root_prefix)
|
273
|
-
|
274
|
-
self.class.namespace_inheritable_to_nil(:root_prefix)
|
275
|
-
|
276
|
-
yield
|
277
|
-
|
278
|
-
self.class.namespace_inheritable(:root_prefix, old_prefix)
|
242
|
+
self.class.namespace_inheritable(:root_prefix, old_root_prefix)
|
279
243
|
end
|
280
244
|
end
|
281
245
|
end
|
data/lib/grape/api.rb
CHANGED
@@ -40,7 +40,7 @@ module Grape
|
|
40
40
|
# an instance that will be used to create the set up but will not be mounted
|
41
41
|
def initial_setup(base_instance_parent)
|
42
42
|
@instances = []
|
43
|
-
@setup =
|
43
|
+
@setup = []
|
44
44
|
@base_parent = base_instance_parent
|
45
45
|
@base_instance = mount_instance
|
46
46
|
end
|
@@ -78,20 +78,11 @@ module Grape
|
|
78
78
|
instance_for_rack.call(...)
|
79
79
|
end
|
80
80
|
|
81
|
-
# Alleviates problems with autoloading by tring to search for the constant
|
82
|
-
def const_missing(*args)
|
83
|
-
if base_instance.const_defined?(*args)
|
84
|
-
base_instance.const_get(*args)
|
85
|
-
else
|
86
|
-
super
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
81
|
# The remountable class can have a configuration hash to provide some dynamic class-level variables.
|
91
82
|
# For instance, a description could be done using: `desc configuration[:description]` if it may vary
|
92
83
|
# depending on where the endpoint is mounted. Use with care, if you find yourself using configuration
|
93
84
|
# too much, you may actually want to provide a new API rather than remount it.
|
94
|
-
def mount_instance(
|
85
|
+
def mount_instance(opts = {})
|
95
86
|
instance = Class.new(@base_parent)
|
96
87
|
instance.configuration = Grape::Util::EndpointConfiguration.new(opts[:configuration] || {})
|
97
88
|
instance.base = self
|
data/lib/grape/content_types.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module ContentTypes
|
5
|
-
|
5
|
+
module_function
|
6
6
|
|
7
7
|
# Content types are listed in order of preference.
|
8
|
-
|
8
|
+
DEFAULTS = {
|
9
9
|
xml: 'application/xml',
|
10
10
|
serializable_hash: 'application/json',
|
11
11
|
json: 'application/json',
|
@@ -13,13 +13,18 @@ module Grape
|
|
13
13
|
txt: 'text/plain'
|
14
14
|
}.freeze
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
MIME_TYPES = Grape::ContentTypes::DEFAULTS.except(:serializable_hash).invert.freeze
|
17
|
+
|
18
|
+
def content_types_for(from_settings)
|
19
|
+
from_settings.presence || DEFAULTS
|
20
|
+
end
|
21
|
+
|
22
|
+
def mime_types_for(from_settings)
|
23
|
+
return MIME_TYPES if from_settings == Grape::ContentTypes::DEFAULTS
|
20
24
|
|
21
|
-
|
22
|
-
|
25
|
+
from_settings.each_with_object({}) do |(k, v), types_without_params|
|
26
|
+
# remove optional parameter
|
27
|
+
types_without_params[v.split(';', 2).first] = k
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
data/lib/grape/dsl/desc.rb
CHANGED
@@ -70,33 +70,23 @@ module Grape
|
|
70
70
|
# # ...
|
71
71
|
# end
|
72
72
|
#
|
73
|
-
def desc(description, options =
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
elsif configuration.is_a?(Hash)
|
81
|
-
configuration
|
82
|
-
end
|
83
|
-
end
|
84
|
-
endpoint_configuration ||= {}
|
85
|
-
config_class = desc_container(endpoint_configuration)
|
73
|
+
def desc(description, options = nil, &config_block)
|
74
|
+
opts =
|
75
|
+
if config_block
|
76
|
+
desc_container(endpoint_configuration).then do |config_class|
|
77
|
+
config_class.configure do
|
78
|
+
description(description)
|
79
|
+
end
|
86
80
|
|
87
|
-
|
88
|
-
|
81
|
+
config_class.configure(&config_block)
|
82
|
+
config_class.settings
|
83
|
+
end
|
84
|
+
else
|
85
|
+
options&.merge(description: description) || { description: description }
|
89
86
|
end
|
90
87
|
|
91
|
-
|
92
|
-
|
93
|
-
options = config_class.settings
|
94
|
-
else
|
95
|
-
options = options.merge(description: description)
|
96
|
-
end
|
97
|
-
|
98
|
-
namespace_setting :description, options
|
99
|
-
route_setting :description, options
|
88
|
+
namespace_setting :description, opts
|
89
|
+
route_setting :description, opts
|
100
90
|
end
|
101
91
|
|
102
92
|
# Returns an object which configures itself via an instance-context DSL.
|
@@ -116,6 +106,19 @@ module Grape
|
|
116
106
|
end
|
117
107
|
end
|
118
108
|
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def endpoint_configuration
|
113
|
+
return {} unless defined?(configuration)
|
114
|
+
|
115
|
+
if configuration.respond_to?(:evaluate)
|
116
|
+
configuration.evaluate
|
117
|
+
# Within `given` or `mounted blocks` the configuration is already evaluated
|
118
|
+
elsif configuration.is_a?(Hash)
|
119
|
+
configuration
|
120
|
+
end
|
121
|
+
end
|
119
122
|
end
|
120
123
|
end
|
121
124
|
end
|
data/lib/grape/dsl/helpers.rb
CHANGED
@@ -33,18 +33,22 @@ module Grape
|
|
33
33
|
# end
|
34
34
|
#
|
35
35
|
def helpers(*new_modules, &block)
|
36
|
-
include_new_modules(new_modules)
|
37
|
-
include_block(block)
|
36
|
+
include_new_modules(new_modules)
|
37
|
+
include_block(block)
|
38
38
|
include_all_in_scope if !block && new_modules.empty?
|
39
39
|
end
|
40
40
|
|
41
41
|
protected
|
42
42
|
|
43
43
|
def include_new_modules(modules)
|
44
|
+
return if modules.empty?
|
45
|
+
|
44
46
|
modules.each { |mod| make_inclusion(mod) }
|
45
47
|
end
|
46
48
|
|
47
49
|
def include_block(block)
|
50
|
+
return unless block
|
51
|
+
|
48
52
|
Module.new.tap do |mod|
|
49
53
|
make_inclusion(mod) { mod.class_eval(&block) }
|
50
54
|
end
|
@@ -58,7 +62,7 @@ module Grape
|
|
58
62
|
|
59
63
|
def include_all_in_scope
|
60
64
|
Module.new.tap do |mod|
|
61
|
-
namespace_stackable(:helpers).each { |mod_to_include| mod.
|
65
|
+
namespace_stackable(:helpers).each { |mod_to_include| mod.include mod_to_include }
|
62
66
|
change!
|
63
67
|
end
|
64
68
|
end
|
@@ -26,8 +26,8 @@ module Grape
|
|
26
26
|
# has completed
|
27
27
|
module PostBeforeFilter
|
28
28
|
def declared(passed_params, options = {}, declared_params = nil, params_nested_path = [])
|
29
|
-
options
|
30
|
-
declared_params ||= optioned_declared_params(
|
29
|
+
options.reverse_merge!(include_missing: true, include_parent_namespaces: true, evaluate_given: false)
|
30
|
+
declared_params ||= optioned_declared_params(options[:include_parent_namespaces])
|
31
31
|
|
32
32
|
res = if passed_params.is_a?(Array)
|
33
33
|
declared_array(passed_params, options, declared_params, params_nested_path)
|
@@ -120,8 +120,8 @@ module Grape
|
|
120
120
|
options[:stringify] ? declared_param.to_s : declared_param.to_sym
|
121
121
|
end
|
122
122
|
|
123
|
-
def optioned_declared_params(
|
124
|
-
declared_params = if
|
123
|
+
def optioned_declared_params(include_parent_namespaces)
|
124
|
+
declared_params = if include_parent_namespaces
|
125
125
|
# Declared params including parent namespaces
|
126
126
|
route_setting(:declared_params)
|
127
127
|
else
|
@@ -170,7 +170,12 @@ module Grape
|
|
170
170
|
def error!(message, status = nil, additional_headers = nil, backtrace = nil, original_exception = nil)
|
171
171
|
status = self.status(status || namespace_inheritable(:default_error_status))
|
172
172
|
headers = additional_headers.present? ? header.merge(additional_headers) : header
|
173
|
-
throw :error,
|
173
|
+
throw :error,
|
174
|
+
message: message,
|
175
|
+
status: status,
|
176
|
+
headers: headers,
|
177
|
+
backtrace: backtrace,
|
178
|
+
original_exception: original_exception
|
174
179
|
end
|
175
180
|
|
176
181
|
# Creates a Rack response based on the provided message, status, and headers.
|
@@ -194,10 +199,9 @@ module Grape
|
|
194
199
|
# Redirect to a new url.
|
195
200
|
#
|
196
201
|
# @param url [String] The url to be redirect.
|
197
|
-
# @param
|
198
|
-
#
|
199
|
-
|
200
|
-
def redirect(url, permanent: false, body: nil, **_options)
|
202
|
+
# @param permanent [Boolean] default false.
|
203
|
+
# @param body default a short message including the URL.
|
204
|
+
def redirect(url, permanent: false, body: nil)
|
201
205
|
body_message = body
|
202
206
|
if permanent
|
203
207
|
status 301
|
@@ -300,20 +304,6 @@ module Grape
|
|
300
304
|
body false
|
301
305
|
end
|
302
306
|
|
303
|
-
# Deprecated method to send files to the client. Use `sendfile` or `stream`
|
304
|
-
def file(value = nil)
|
305
|
-
if value.is_a?(String)
|
306
|
-
Grape.deprecator.warn('Use sendfile or stream to send files.')
|
307
|
-
sendfile(value)
|
308
|
-
elsif !value.is_a?(NilClass)
|
309
|
-
Grape.deprecator.warn('Use stream to use a Stream object.')
|
310
|
-
stream(value)
|
311
|
-
else
|
312
|
-
Grape.deprecator.warn('Use sendfile or stream to send files.')
|
313
|
-
sendfile
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
307
|
# Allows you to send a file to the client via sendfile.
|
318
308
|
#
|
319
309
|
# @example
|
@@ -461,7 +451,11 @@ module Grape
|
|
461
451
|
end
|
462
452
|
|
463
453
|
def http_version
|
464
|
-
env
|
454
|
+
env.fetch(Grape::Http::Headers::HTTP_VERSION) { env[Rack::SERVER_PROTOCOL] }
|
455
|
+
end
|
456
|
+
|
457
|
+
def api_format(format)
|
458
|
+
env[Grape::Env::API_FORMAT] = format
|
465
459
|
end
|
466
460
|
|
467
461
|
def context
|
data/lib/grape/dsl/parameters.rb
CHANGED
@@ -136,7 +136,7 @@ module Grape
|
|
136
136
|
require_required_and_optional_fields(attrs.first, opts)
|
137
137
|
else
|
138
138
|
validate_attributes(attrs, opts, &block)
|
139
|
-
block ? new_scope(orig_attrs, &block) : push_declared_params(attrs,
|
139
|
+
block ? new_scope(orig_attrs, &block) : push_declared_params(attrs, opts.slice(:as))
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
@@ -162,7 +162,7 @@ module Grape
|
|
162
162
|
else
|
163
163
|
validate_attributes(attrs, opts, &block)
|
164
164
|
|
165
|
-
block ? new_scope(orig_attrs, true, &block) : push_declared_params(attrs,
|
165
|
+
block ? new_scope(orig_attrs, true, &block) : push_declared_params(attrs, opts.slice(:as))
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
@@ -17,18 +17,16 @@ module Grape
|
|
17
17
|
# Specify the format for the API's serializers.
|
18
18
|
# May be `:json`, `:xml`, `:txt`, etc.
|
19
19
|
def format(new_format = nil)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
namespace_inheritable(:format)
|
31
|
-
end
|
20
|
+
return namespace_inheritable(:format) unless new_format
|
21
|
+
|
22
|
+
symbolic_new_format = new_format.to_sym
|
23
|
+
namespace_inheritable(:format, symbolic_new_format)
|
24
|
+
namespace_inheritable(:default_error_formatter, Grape::ErrorFormatter.formatter_for(symbolic_new_format))
|
25
|
+
|
26
|
+
content_type = content_types[symbolic_new_format]
|
27
|
+
raise Grape::Exceptions::MissingMimeType.new(new_format) unless content_type
|
28
|
+
|
29
|
+
namespace_stackable(:content_types, symbolic_new_format => content_type)
|
32
30
|
end
|
33
31
|
|
34
32
|
# Specify a custom formatter for a content-type.
|
@@ -43,12 +41,10 @@ module Grape
|
|
43
41
|
|
44
42
|
# Specify a default error formatter.
|
45
43
|
def default_error_formatter(new_formatter_name = nil)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
namespace_inheritable(:default_error_formatter)
|
51
|
-
end
|
44
|
+
return namespace_inheritable(:default_error_formatter) unless new_formatter_name
|
45
|
+
|
46
|
+
new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name)
|
47
|
+
namespace_inheritable(:default_error_formatter, new_formatter)
|
52
48
|
end
|
53
49
|
|
54
50
|
def error_formatter(format, options)
|
data/lib/grape/dsl/routing.rb
CHANGED
@@ -175,19 +175,12 @@ module Grape
|
|
175
175
|
# end
|
176
176
|
# end
|
177
177
|
def namespace(space = nil, options = {}, &block)
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
@namespace_description = (@namespace_description || {}).deep_merge(namespace_setting(:description) || {})
|
184
|
-
nest(block) do
|
185
|
-
namespace_stackable(:namespace, Namespace.new(space, **options)) if space
|
186
|
-
end
|
187
|
-
@namespace_description = previous_namespace_description
|
178
|
+
return Namespace.joined_space_path(namespace_stackable(:namespace)) unless space || block
|
179
|
+
|
180
|
+
within_namespace do
|
181
|
+
nest(block) do
|
182
|
+
namespace_stackable(:namespace, Namespace.new(space, options)) if space
|
188
183
|
end
|
189
|
-
else
|
190
|
-
Namespace.joined_space_path(namespace_stackable(:namespace))
|
191
184
|
end
|
192
185
|
end
|
193
186
|
|