grape 2.1.0 → 2.2.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 +46 -0
- data/README.md +4 -3
- data/UPGRADING.md +8 -0
- data/grape.gemspec +2 -1
- data/lib/grape/api/instance.rb +1 -1
- data/lib/grape/api.rb +2 -2
- data/lib/grape/content_types.rb +13 -8
- data/lib/grape/dsl/helpers.rb +7 -3
- data/lib/grape/dsl/inside_route.rb +14 -3
- data/lib/grape/dsl/parameters.rb +1 -1
- data/lib/grape/dsl/request_response.rb +14 -18
- data/lib/grape/endpoint.rb +34 -23
- data/lib/grape/error_formatter/json.rb +13 -4
- data/lib/grape/error_formatter.rb +13 -25
- data/lib/grape/exceptions/validation_errors.rb +1 -1
- data/lib/grape/formatter.rb +15 -25
- data/lib/grape/locale/en.yml +1 -0
- data/lib/grape/middleware/base.rb +14 -13
- data/lib/grape/middleware/error.rb +13 -11
- data/lib/grape/middleware/formatter.rb +2 -2
- data/lib/grape/middleware/stack.rb +2 -2
- data/lib/grape/middleware/versioner/accept_version_header.rb +8 -31
- data/lib/grape/middleware/versioner/header.rb +95 -10
- data/lib/grape/middleware/versioner/param.rb +5 -21
- data/lib/grape/middleware/versioner/path.rb +11 -31
- data/lib/grape/middleware/versioner.rb +5 -14
- data/lib/grape/middleware/versioner_helpers.rb +75 -0
- data/lib/grape/parser.rb +8 -24
- data/lib/grape/router.rb +2 -1
- data/lib/grape/validations/attributes_iterator.rb +1 -0
- data/lib/grape/validations/params_scope.rb +12 -10
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +1 -1
- data/lib/grape/validations/validators/length_validator.rb +10 -3
- data/lib/grape/version.rb +1 -1
- metadata +8 -9
- data/lib/grape/util/accept/header.rb +0 -19
- data/lib/grape/util/accept_header_handler.rb +0 -105
- data/lib/grape/util/registrable.rb +0 -15
@@ -7,20 +7,25 @@ module Grape
|
|
7
7
|
def initialize(attrs, options, required, scope, **opts)
|
8
8
|
@min = options[:min]
|
9
9
|
@max = options[:max]
|
10
|
+
@is = options[:is]
|
10
11
|
|
11
12
|
super
|
12
13
|
|
13
14
|
raise ArgumentError, 'min must be an integer greater than or equal to zero' if !@min.nil? && (!@min.is_a?(Integer) || @min.negative?)
|
14
15
|
raise ArgumentError, 'max must be an integer greater than or equal to zero' if !@max.nil? && (!@max.is_a?(Integer) || @max.negative?)
|
15
16
|
raise ArgumentError, "min #{@min} cannot be greater than max #{@max}" if !@min.nil? && !@max.nil? && @min > @max
|
17
|
+
|
18
|
+
return if @is.nil?
|
19
|
+
raise ArgumentError, 'is must be an integer greater than zero' if !@is.is_a?(Integer) || !@is.positive?
|
20
|
+
raise ArgumentError, 'is cannot be combined with min or max' if !@min.nil? || !@max.nil?
|
16
21
|
end
|
17
22
|
|
18
23
|
def validate_param!(attr_name, params)
|
19
24
|
param = params[attr_name]
|
20
25
|
|
21
|
-
|
26
|
+
return unless param.respond_to?(:length)
|
22
27
|
|
23
|
-
return unless (!@min.nil? && param.length < @min) || (!@max.nil? && param.length > @max)
|
28
|
+
return unless (!@min.nil? && param.length < @min) || (!@max.nil? && param.length > @max) || (!@is.nil? && param.length != @is)
|
24
29
|
|
25
30
|
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: build_message)
|
26
31
|
end
|
@@ -32,8 +37,10 @@ module Grape
|
|
32
37
|
format I18n.t(:length, scope: 'grape.errors.messages'), min: @min, max: @max
|
33
38
|
elsif @min
|
34
39
|
format I18n.t(:length_min, scope: 'grape.errors.messages'), min: @min
|
35
|
-
|
40
|
+
elsif @max
|
36
41
|
format I18n.t(:length_max, scope: 'grape.errors.messages'), max: @max
|
42
|
+
else
|
43
|
+
format I18n.t(:length_is, scope: 'grape.errors.messages'), is: @is
|
37
44
|
end
|
38
45
|
end
|
39
46
|
end
|
data/lib/grape/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grape
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Bleigh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -172,6 +172,7 @@ files:
|
|
172
172
|
- lib/grape/middleware/versioner/header.rb
|
173
173
|
- lib/grape/middleware/versioner/param.rb
|
174
174
|
- lib/grape/middleware/versioner/path.rb
|
175
|
+
- lib/grape/middleware/versioner_helpers.rb
|
175
176
|
- lib/grape/namespace.rb
|
176
177
|
- lib/grape/parser.rb
|
177
178
|
- lib/grape/parser/json.rb
|
@@ -189,8 +190,6 @@ files:
|
|
189
190
|
- lib/grape/serve_stream/sendfile_response.rb
|
190
191
|
- lib/grape/serve_stream/stream_response.rb
|
191
192
|
- lib/grape/types/invalid_value.rb
|
192
|
-
- lib/grape/util/accept/header.rb
|
193
|
-
- lib/grape/util/accept_header_handler.rb
|
194
193
|
- lib/grape/util/base_inheritable.rb
|
195
194
|
- lib/grape/util/cache.rb
|
196
195
|
- lib/grape/util/endpoint_configuration.rb
|
@@ -204,7 +203,6 @@ files:
|
|
204
203
|
- lib/grape/util/lazy/value_enumerable.rb
|
205
204
|
- lib/grape/util/lazy/value_hash.rb
|
206
205
|
- lib/grape/util/media_type.rb
|
207
|
-
- lib/grape/util/registrable.rb
|
208
206
|
- lib/grape/util/reverse_stackable_values.rb
|
209
207
|
- lib/grape/util/stackable_values.rb
|
210
208
|
- lib/grape/util/strict_hash_configuration.rb
|
@@ -252,9 +250,10 @@ licenses:
|
|
252
250
|
- MIT
|
253
251
|
metadata:
|
254
252
|
bug_tracker_uri: https://github.com/ruby-grape/grape/issues
|
255
|
-
changelog_uri: https://github.com/ruby-grape/grape/blob/v2.
|
256
|
-
documentation_uri: https://www.rubydoc.info/gems/grape/2.
|
257
|
-
source_code_uri: https://github.com/ruby-grape/grape/tree/v2.
|
253
|
+
changelog_uri: https://github.com/ruby-grape/grape/blob/v2.2.0/CHANGELOG.md
|
254
|
+
documentation_uri: https://www.rubydoc.info/gems/grape/2.2.0
|
255
|
+
source_code_uri: https://github.com/ruby-grape/grape/tree/v2.2.0
|
256
|
+
rubygems_mfa_required: 'true'
|
258
257
|
post_install_message:
|
259
258
|
rdoc_options: []
|
260
259
|
require_paths:
|
@@ -270,7 +269,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
270
269
|
- !ruby/object:Gem::Version
|
271
270
|
version: '0'
|
272
271
|
requirements: []
|
273
|
-
rubygems_version: 3.5.
|
272
|
+
rubygems_version: 3.5.13
|
274
273
|
signing_key:
|
275
274
|
specification_version: 4
|
276
275
|
summary: A simple Ruby framework for building REST-like APIs.
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Grape
|
4
|
-
module Util
|
5
|
-
module Accept
|
6
|
-
module Header
|
7
|
-
ALLOWED_CHARACTERS = %r{^([a-z*]+)/([a-z0-9*&\^\-_#{$ERROR_INFO}.+]+)(?:;([a-z0-9=;]+))?$}.freeze
|
8
|
-
class << self
|
9
|
-
# Corrected version of https://github.com/mjackson/rack-accept/blob/master/lib/rack/accept/header.rb#L40-L44
|
10
|
-
def parse_media_type(media_type)
|
11
|
-
# see http://tools.ietf.org/html/rfc6838#section-4.2 for allowed characters in media type names
|
12
|
-
m = media_type&.match(ALLOWED_CHARACTERS)
|
13
|
-
m ? [m[1], m[2], m[3] || ''] : []
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Grape
|
4
|
-
module Util
|
5
|
-
class AcceptHeaderHandler
|
6
|
-
attr_reader :accept_header, :versions, :vendor, :strict, :cascade
|
7
|
-
|
8
|
-
def initialize(accept_header:, versions:, **options)
|
9
|
-
@accept_header = accept_header
|
10
|
-
@versions = versions
|
11
|
-
@vendor = options.fetch(:vendor, nil)
|
12
|
-
@strict = options.fetch(:strict, false)
|
13
|
-
@cascade = options.fetch(:cascade, true)
|
14
|
-
end
|
15
|
-
|
16
|
-
def match_best_quality_media_type!(content_types: Grape::ContentTypes::CONTENT_TYPES, allowed_methods: nil)
|
17
|
-
return unless vendor
|
18
|
-
|
19
|
-
strict_header_checks!
|
20
|
-
media_type = Grape::Util::MediaType.best_quality(accept_header, available_media_types(content_types))
|
21
|
-
if media_type
|
22
|
-
yield media_type
|
23
|
-
else
|
24
|
-
fail!(allowed_methods)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def strict_header_checks!
|
31
|
-
return unless strict
|
32
|
-
|
33
|
-
accept_header_check!
|
34
|
-
version_and_vendor_check!
|
35
|
-
end
|
36
|
-
|
37
|
-
def accept_header_check!
|
38
|
-
return if accept_header.present?
|
39
|
-
|
40
|
-
invalid_accept_header!('Accept header must be set.')
|
41
|
-
end
|
42
|
-
|
43
|
-
def version_and_vendor_check!
|
44
|
-
return if versions.blank? || version_and_vendor?
|
45
|
-
|
46
|
-
invalid_accept_header!('API vendor or version not found.')
|
47
|
-
end
|
48
|
-
|
49
|
-
def q_values_mime_types
|
50
|
-
@q_values_mime_types ||= Rack::Utils.q_values(accept_header).map(&:first)
|
51
|
-
end
|
52
|
-
|
53
|
-
def version_and_vendor?
|
54
|
-
q_values_mime_types.any? { |mime_type| Grape::Util::MediaType.match?(mime_type) }
|
55
|
-
end
|
56
|
-
|
57
|
-
def invalid_accept_header!(message)
|
58
|
-
raise Grape::Exceptions::InvalidAcceptHeader.new(message, error_headers)
|
59
|
-
end
|
60
|
-
|
61
|
-
def invalid_version_header!(message)
|
62
|
-
raise Grape::Exceptions::InvalidVersionHeader.new(message, error_headers)
|
63
|
-
end
|
64
|
-
|
65
|
-
def fail!(grape_allowed_methods)
|
66
|
-
return grape_allowed_methods if grape_allowed_methods.present?
|
67
|
-
|
68
|
-
media_types = q_values_mime_types.map { |mime_type| Grape::Util::MediaType.parse(mime_type) }
|
69
|
-
vendor_not_found!(media_types) || version_not_found!(media_types)
|
70
|
-
end
|
71
|
-
|
72
|
-
def vendor_not_found!(media_types)
|
73
|
-
return unless media_types.all? { |media_type| media_type&.vendor && media_type.vendor != vendor }
|
74
|
-
|
75
|
-
invalid_accept_header!('API vendor not found.')
|
76
|
-
end
|
77
|
-
|
78
|
-
def version_not_found!(media_types)
|
79
|
-
return unless media_types.all? { |media_type| media_type&.version && versions.exclude?(media_type.version) }
|
80
|
-
|
81
|
-
invalid_version_header!('API version not found.')
|
82
|
-
end
|
83
|
-
|
84
|
-
def error_headers
|
85
|
-
cascade ? { Grape::Http::Headers::X_CASCADE => 'pass' } : {}
|
86
|
-
end
|
87
|
-
|
88
|
-
def available_media_types(content_types)
|
89
|
-
[].tap do |available_media_types|
|
90
|
-
base_media_type = "application/vnd.#{vendor}"
|
91
|
-
content_types.each_key do |extension|
|
92
|
-
versions&.reverse_each do |version|
|
93
|
-
available_media_types << "#{base_media_type}-#{version}+#{extension}"
|
94
|
-
available_media_types << "#{base_media_type}-#{version}"
|
95
|
-
end
|
96
|
-
available_media_types << "#{base_media_type}+#{extension}"
|
97
|
-
end
|
98
|
-
|
99
|
-
available_media_types << base_media_type
|
100
|
-
available_media_types.concat(content_types.values.flatten)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Grape
|
4
|
-
module Util
|
5
|
-
module Registrable
|
6
|
-
def default_elements
|
7
|
-
@default_elements ||= {}
|
8
|
-
end
|
9
|
-
|
10
|
-
def register(format, element)
|
11
|
-
default_elements[format] = element unless default_elements[format]
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|