grape 2.0.0 → 2.4.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 +151 -1
- data/CONTRIBUTING.md +1 -1
- data/README.md +404 -334
- data/UPGRADING.md +279 -7
- data/grape.gemspec +8 -8
- data/lib/grape/api/instance.rb +34 -66
- data/lib/grape/api.rb +47 -70
- data/lib/grape/content_types.rb +13 -10
- data/lib/grape/cookies.rb +31 -24
- data/lib/grape/dry_types.rb +0 -2
- data/lib/grape/dsl/api.rb +0 -2
- data/lib/grape/dsl/desc.rb +49 -44
- data/lib/grape/dsl/headers.rb +2 -2
- data/lib/grape/dsl/helpers.rb +8 -4
- data/lib/grape/dsl/inside_route.rb +67 -54
- data/lib/grape/dsl/parameters.rb +10 -9
- data/lib/grape/dsl/request_response.rb +14 -18
- data/lib/grape/dsl/routing.rb +34 -17
- data/lib/grape/dsl/validations.rb +13 -0
- data/lib/grape/endpoint.rb +120 -118
- data/lib/grape/{util/env.rb → env.rb} +0 -5
- data/lib/grape/error_formatter/base.rb +51 -21
- data/lib/grape/error_formatter/json.rb +7 -15
- data/lib/grape/error_formatter/serializable_hash.rb +7 -0
- data/lib/grape/error_formatter/txt.rb +11 -17
- 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/conflicting_types.rb +11 -0
- data/lib/grape/exceptions/invalid_parameters.rb +11 -0
- data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
- data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
- data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
- data/lib/grape/exceptions/validation.rb +5 -6
- data/lib/grape/exceptions/validation_array_errors.rb +1 -0
- data/lib/grape/exceptions/validation_errors.rb +4 -6
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +2 -5
- data/lib/grape/extensions/hash.rb +7 -2
- data/lib/grape/extensions/hashie/mash.rb +3 -5
- 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/{util/json.rb → json.rb} +1 -3
- data/lib/grape/locale/en.yml +46 -42
- data/lib/grape/middleware/auth/base.rb +11 -34
- data/lib/grape/middleware/auth/dsl.rb +23 -31
- data/lib/grape/middleware/base.rb +41 -23
- data/lib/grape/middleware/error.rb +77 -76
- data/lib/grape/middleware/formatter.rb +48 -79
- data/lib/grape/middleware/globals.rb +1 -3
- data/lib/grape/middleware/stack.rb +26 -37
- data/lib/grape/middleware/versioner/accept_version_header.rb +6 -33
- data/lib/grape/middleware/versioner/base.rb +74 -0
- data/lib/grape/middleware/versioner/header.rb +59 -126
- data/lib/grape/middleware/versioner/param.rb +4 -25
- data/lib/grape/middleware/versioner/path.rb +10 -34
- data/lib/grape/middleware/versioner.rb +7 -14
- data/lib/grape/namespace.rb +4 -5
- data/lib/grape/params_builder/base.rb +18 -0
- data/lib/grape/params_builder/hash.rb +11 -0
- data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
- data/lib/grape/params_builder/hashie_mash.rb +11 -0
- data/lib/grape/params_builder.rb +32 -0
- data/lib/grape/parser/base.rb +16 -0
- data/lib/grape/parser/json.rb +6 -8
- data/lib/grape/parser/xml.rb +6 -8
- data/lib/grape/parser.rb +5 -23
- data/lib/grape/path.rb +38 -60
- data/lib/grape/request.rb +161 -30
- data/lib/grape/router/base_route.rb +39 -0
- data/lib/grape/router/greedy_route.rb +20 -0
- data/lib/grape/router/pattern.rb +45 -31
- data/lib/grape/router/route.rb +28 -57
- data/lib/grape/router.rb +56 -43
- data/lib/grape/util/base_inheritable.rb +4 -4
- data/lib/grape/util/cache.rb +0 -3
- data/lib/grape/util/endpoint_configuration.rb +1 -1
- data/lib/grape/util/header.rb +13 -0
- data/lib/grape/util/inheritable_values.rb +0 -2
- data/lib/grape/util/lazy/block.rb +29 -0
- data/lib/grape/util/lazy/value.rb +38 -0
- data/lib/grape/util/lazy/value_array.rb +21 -0
- data/lib/grape/util/lazy/value_enumerable.rb +34 -0
- data/lib/grape/util/lazy/value_hash.rb +21 -0
- data/lib/grape/util/media_type.rb +70 -0
- data/lib/grape/util/registry.rb +27 -0
- data/lib/grape/util/reverse_stackable_values.rb +1 -6
- data/lib/grape/util/stackable_values.rb +1 -6
- data/lib/grape/util/strict_hash_configuration.rb +3 -3
- data/lib/grape/validations/attributes_doc.rb +38 -36
- data/lib/grape/validations/attributes_iterator.rb +1 -0
- data/lib/grape/validations/contract_scope.rb +34 -0
- data/lib/grape/validations/params_scope.rb +36 -32
- data/lib/grape/validations/types/array_coercer.rb +0 -2
- data/lib/grape/validations/types/dry_type_coercer.rb +9 -15
- data/lib/grape/validations/types/json.rb +0 -2
- data/lib/grape/validations/types/primitive_coercer.rb +0 -2
- data/lib/grape/validations/types/set_coercer.rb +0 -3
- data/lib/grape/validations/types.rb +0 -3
- 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 +8 -11
- 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 +6 -2
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +1 -1
- data/lib/grape/validations/validators/except_values_validator.rb +2 -2
- data/lib/grape/validations/validators/length_validator.rb +49 -0
- data/lib/grape/validations/validators/presence_validator.rb +1 -1
- data/lib/grape/validations/validators/regexp_validator.rb +2 -2
- data/lib/grape/validations/validators/values_validator.rb +20 -57
- data/lib/grape/validations.rb +8 -21
- data/lib/grape/version.rb +1 -1
- data/lib/grape/{util/xml.rb → xml.rb} +1 -1
- data/lib/grape.rb +42 -274
- metadata +45 -44
- data/lib/grape/eager_load.rb +0 -20
- data/lib/grape/http/headers.rb +0 -71
- data/lib/grape/middleware/helpers.rb +0 -12
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
- data/lib/grape/router/attribute_translator.rb +0 -63
- data/lib/grape/util/lazy_block.rb +0 -27
- data/lib/grape/util/lazy_object.rb +0 -43
- data/lib/grape/util/lazy_value.rb +0 -91
- data/lib/grape/util/registrable.rb +0 -15
- data/lib/grape/validations/types/build_coercer.rb +0 -94
data/lib/grape/parser/json.rb
CHANGED
@@ -2,14 +2,12 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Parser
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
rescue
|
10
|
-
|
11
|
-
raise Grape::Exceptions::InvalidMessageBody.new('application/json')
|
12
|
-
end
|
5
|
+
class Json < Base
|
6
|
+
def self.call(object, _env)
|
7
|
+
::Grape::Json.load(object)
|
8
|
+
rescue ::Grape::Json::ParseError
|
9
|
+
# handle JSON parsing errors via the rescue handlers or provide error message
|
10
|
+
raise Grape::Exceptions::InvalidMessageBody.new('application/json')
|
13
11
|
end
|
14
12
|
end
|
15
13
|
end
|
data/lib/grape/parser/xml.rb
CHANGED
@@ -2,14 +2,12 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Parser
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
rescue
|
10
|
-
|
11
|
-
raise Grape::Exceptions::InvalidMessageBody.new('application/xml')
|
12
|
-
end
|
5
|
+
class Xml < Base
|
6
|
+
def self.call(object, _env)
|
7
|
+
::Grape::Xml.parse(object)
|
8
|
+
rescue ::Grape::Xml::ParseError
|
9
|
+
# handle XML parsing errors via the rescue handlers or provide error message
|
10
|
+
raise Grape::Exceptions::InvalidMessageBody.new('application/xml')
|
13
11
|
end
|
14
12
|
end
|
15
13
|
end
|
data/lib/grape/parser.rb
CHANGED
@@ -2,32 +2,14 @@
|
|
2
2
|
|
3
3
|
module Grape
|
4
4
|
module Parser
|
5
|
-
extend Util::
|
5
|
+
extend Grape::Util::Registry
|
6
6
|
|
7
|
-
|
8
|
-
def builtin_parsers
|
9
|
-
@builtin_parsers ||= {
|
10
|
-
json: Grape::Parser::Json,
|
11
|
-
jsonapi: Grape::Parser::Json,
|
12
|
-
xml: Grape::Parser::Xml
|
13
|
-
}
|
14
|
-
end
|
7
|
+
module_function
|
15
8
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
9
|
+
def parser_for(format, parsers = nil)
|
10
|
+
return parsers[format] if parsers&.key?(format)
|
19
11
|
|
20
|
-
|
21
|
-
spec = parsers(**options)[api_format]
|
22
|
-
case spec
|
23
|
-
when nil
|
24
|
-
nil
|
25
|
-
when Symbol
|
26
|
-
method(spec)
|
27
|
-
else
|
28
|
-
spec
|
29
|
-
end
|
30
|
-
end
|
12
|
+
registry[format]
|
31
13
|
end
|
32
14
|
end
|
33
15
|
end
|
data/lib/grape/path.rb
CHANGED
@@ -1,98 +1,76 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'grape/util/cache'
|
4
|
-
|
5
3
|
module Grape
|
6
4
|
# Represents a path to an endpoint.
|
7
5
|
class Path
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
DEFAULT_FORMAT_SEGMENT = '(/.:format)'
|
7
|
+
NO_VERSIONING_WITH_VALID_PATH_FORMAT_SEGMENT = '(.:format)'
|
8
|
+
VERSION_SEGMENT = ':version'
|
11
9
|
|
12
|
-
attr_reader :
|
10
|
+
attr_reader :origin, :suffix
|
13
11
|
|
14
|
-
def initialize(raw_path,
|
15
|
-
@
|
16
|
-
@
|
17
|
-
@settings = settings
|
12
|
+
def initialize(raw_path, raw_namespace, settings)
|
13
|
+
@origin = PartsCache[build_parts(raw_path, raw_namespace, settings)]
|
14
|
+
@suffix = build_suffix(raw_path, raw_namespace, settings)
|
18
15
|
end
|
19
16
|
|
20
|
-
def
|
21
|
-
|
17
|
+
def to_s
|
18
|
+
"#{origin}#{suffix}"
|
22
19
|
end
|
23
20
|
|
24
|
-
|
25
|
-
split_setting(:root_prefix)
|
26
|
-
end
|
21
|
+
private
|
27
22
|
|
28
|
-
def
|
29
|
-
if
|
30
|
-
(settings[:format]
|
23
|
+
def build_suffix(raw_path, raw_namespace, settings)
|
24
|
+
if uses_specific_format?(settings)
|
25
|
+
"(.#{settings[:format]})"
|
26
|
+
elsif !uses_path_versioning?(settings) || (valid_part?(raw_namespace) || valid_part?(raw_path))
|
27
|
+
NO_VERSIONING_WITH_VALID_PATH_FORMAT_SEGMENT
|
31
28
|
else
|
32
|
-
|
29
|
+
DEFAULT_FORMAT_SEGMENT
|
33
30
|
end
|
34
31
|
end
|
35
32
|
|
36
|
-
def
|
37
|
-
|
38
|
-
(
|
39
|
-
|
40
|
-
|
33
|
+
def build_parts(raw_path, raw_namespace, settings)
|
34
|
+
[].tap do |parts|
|
35
|
+
add_part(parts, settings[:mount_path])
|
36
|
+
add_part(parts, settings[:root_prefix])
|
37
|
+
parts << VERSION_SEGMENT if uses_path_versioning?(settings)
|
38
|
+
add_part(parts, raw_namespace)
|
39
|
+
add_part(parts, raw_path)
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
44
|
-
def
|
45
|
-
|
43
|
+
def add_part(parts, value)
|
44
|
+
parts << value if value && not_slash?(value)
|
46
45
|
end
|
47
46
|
|
48
|
-
def
|
49
|
-
|
47
|
+
def not_slash?(value)
|
48
|
+
value != '/'
|
50
49
|
end
|
51
50
|
|
52
|
-
def
|
53
|
-
|
54
|
-
"(.#{settings[:format]})"
|
55
|
-
elsif !uses_path_versioning? || (namespace? || path?)
|
56
|
-
'(.:format)'
|
57
|
-
else
|
58
|
-
'(/.:format)'
|
59
|
-
end
|
60
|
-
end
|
51
|
+
def uses_specific_format?(settings)
|
52
|
+
return false unless settings.key?(:format) && settings.key?(:content_types)
|
61
53
|
|
62
|
-
|
63
|
-
Grape::Router.normalize_path(PartsCache[parts])
|
54
|
+
settings[:format] && Array(settings[:content_types]).size == 1
|
64
55
|
end
|
65
56
|
|
66
|
-
def
|
67
|
-
|
68
|
-
end
|
57
|
+
def uses_path_versioning?(settings)
|
58
|
+
return false unless settings.key?(:version) && settings[:version_options]&.key?(:using)
|
69
59
|
|
70
|
-
|
71
|
-
path_with_suffix
|
60
|
+
settings[:version] && settings[:version_options][:using] == :path
|
72
61
|
end
|
73
62
|
|
74
|
-
|
63
|
+
def valid_part?(part)
|
64
|
+
part&.match?(/^\S/) && not_slash?(part)
|
65
|
+
end
|
75
66
|
|
76
67
|
class PartsCache < Grape::Util::Cache
|
77
68
|
def initialize
|
69
|
+
super
|
78
70
|
@cache = Hash.new do |h, parts|
|
79
|
-
h[parts] =
|
71
|
+
h[parts] = Grape::Router.normalize_path(parts.join('/'))
|
80
72
|
end
|
81
73
|
end
|
82
74
|
end
|
83
|
-
|
84
|
-
def parts
|
85
|
-
parts = [mount_path, root_prefix].compact
|
86
|
-
parts << ':version' if uses_path_versioning?
|
87
|
-
parts << namespace.to_s
|
88
|
-
parts << raw_path.to_s
|
89
|
-
parts.flatten.reject { |part| part == '/' }
|
90
|
-
end
|
91
|
-
|
92
|
-
def split_setting(key)
|
93
|
-
return if settings[key].nil?
|
94
|
-
|
95
|
-
settings[key].to_s.split('/')
|
96
|
-
end
|
97
75
|
end
|
98
76
|
end
|
data/lib/grape/request.rb
CHANGED
@@ -1,58 +1,189 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'grape/util/lazy_object'
|
4
|
-
|
5
3
|
module Grape
|
6
4
|
class Request < Rack::Request
|
7
|
-
|
5
|
+
# Based on rack 3 KNOWN_HEADERS
|
6
|
+
# https://github.com/rack/rack/blob/4f15e7b814922af79605be4b02c5b7c3044ba206/lib/rack/headers.rb#L10
|
7
|
+
|
8
|
+
KNOWN_HEADERS = %w[
|
9
|
+
Accept
|
10
|
+
Accept-CH
|
11
|
+
Accept-Encoding
|
12
|
+
Accept-Language
|
13
|
+
Accept-Patch
|
14
|
+
Accept-Ranges
|
15
|
+
Accept-Version
|
16
|
+
Access-Control-Allow-Credentials
|
17
|
+
Access-Control-Allow-Headers
|
18
|
+
Access-Control-Allow-Methods
|
19
|
+
Access-Control-Allow-Origin
|
20
|
+
Access-Control-Expose-Headers
|
21
|
+
Access-Control-Max-Age
|
22
|
+
Age
|
23
|
+
Allow
|
24
|
+
Alt-Svc
|
25
|
+
Authorization
|
26
|
+
Cache-Control
|
27
|
+
Client-Ip
|
28
|
+
Connection
|
29
|
+
Content-Disposition
|
30
|
+
Content-Encoding
|
31
|
+
Content-Language
|
32
|
+
Content-Length
|
33
|
+
Content-Location
|
34
|
+
Content-MD5
|
35
|
+
Content-Range
|
36
|
+
Content-Security-Policy
|
37
|
+
Content-Security-Policy-Report-Only
|
38
|
+
Content-Type
|
39
|
+
Cookie
|
40
|
+
Date
|
41
|
+
Delta-Base
|
42
|
+
Dnt
|
43
|
+
ETag
|
44
|
+
Expect-CT
|
45
|
+
Expires
|
46
|
+
Feature-Policy
|
47
|
+
Forwarded
|
48
|
+
Host
|
49
|
+
If-Modified-Since
|
50
|
+
If-None-Match
|
51
|
+
IM
|
52
|
+
Last-Modified
|
53
|
+
Link
|
54
|
+
Location
|
55
|
+
NEL
|
56
|
+
P3P
|
57
|
+
Permissions-Policy
|
58
|
+
Pragma
|
59
|
+
Preference-Applied
|
60
|
+
Proxy-Authenticate
|
61
|
+
Public-Key-Pins
|
62
|
+
Range
|
63
|
+
Referer
|
64
|
+
Referrer-Policy
|
65
|
+
Refresh
|
66
|
+
Report-To
|
67
|
+
Retry-After
|
68
|
+
Sec-Fetch-Dest
|
69
|
+
Sec-Fetch-Mode
|
70
|
+
Sec-Fetch-Site
|
71
|
+
Sec-Fetch-User
|
72
|
+
Server
|
73
|
+
Set-Cookie
|
74
|
+
Status
|
75
|
+
Strict-Transport-Security
|
76
|
+
Timing-Allow-Origin
|
77
|
+
Tk
|
78
|
+
Trailer
|
79
|
+
Transfer-Encoding
|
80
|
+
Upgrade
|
81
|
+
Upgrade-Insecure-Requests
|
82
|
+
User-Agent
|
83
|
+
Vary
|
84
|
+
Version
|
85
|
+
Via
|
86
|
+
Warning
|
87
|
+
WWW-Authenticate
|
88
|
+
X-Accel-Buffering
|
89
|
+
X-Accel-Charset
|
90
|
+
X-Accel-Expires
|
91
|
+
X-Accel-Limit-Rate
|
92
|
+
X-Accel-Mapping
|
93
|
+
X-Accel-Redirect
|
94
|
+
X-Access-Token
|
95
|
+
X-Auth-Request-Access-Token
|
96
|
+
X-Auth-Request-Email
|
97
|
+
X-Auth-Request-Groups
|
98
|
+
X-Auth-Request-Preferred-Username
|
99
|
+
X-Auth-Request-Redirect
|
100
|
+
X-Auth-Request-Token
|
101
|
+
X-Auth-Request-User
|
102
|
+
X-Cascade
|
103
|
+
X-Client-Ip
|
104
|
+
X-Content-Duration
|
105
|
+
X-Content-Security-Policy
|
106
|
+
X-Content-Type-Options
|
107
|
+
X-Correlation-Id
|
108
|
+
X-Download-Options
|
109
|
+
X-Forwarded-Access-Token
|
110
|
+
X-Forwarded-Email
|
111
|
+
X-Forwarded-For
|
112
|
+
X-Forwarded-Groups
|
113
|
+
X-Forwarded-Host
|
114
|
+
X-Forwarded-Port
|
115
|
+
X-Forwarded-Preferred-Username
|
116
|
+
X-Forwarded-Proto
|
117
|
+
X-Forwarded-Scheme
|
118
|
+
X-Forwarded-Ssl
|
119
|
+
X-Forwarded-Uri
|
120
|
+
X-Forwarded-User
|
121
|
+
X-Frame-Options
|
122
|
+
X-HTTP-Method-Override
|
123
|
+
X-Permitted-Cross-Domain-Policies
|
124
|
+
X-Powered-By
|
125
|
+
X-Real-IP
|
126
|
+
X-Redirect-By
|
127
|
+
X-Request-Id
|
128
|
+
X-Requested-With
|
129
|
+
X-Runtime
|
130
|
+
X-Sendfile
|
131
|
+
X-Sendfile-Type
|
132
|
+
X-UA-Compatible
|
133
|
+
X-WebKit-CS
|
134
|
+
X-XSS-Protection
|
135
|
+
].each_with_object({}) do |header, response|
|
136
|
+
response["HTTP_#{header.upcase.tr('-', '_')}"] = header
|
137
|
+
end.freeze
|
8
138
|
|
9
139
|
alias rack_params params
|
140
|
+
alias rack_cookies cookies
|
10
141
|
|
11
|
-
def initialize(env,
|
12
|
-
extend options[:build_params_with] || Grape.config.param_builder
|
142
|
+
def initialize(env, build_params_with: nil)
|
13
143
|
super(env)
|
144
|
+
@params_builder = Grape::ParamsBuilder.params_builder_for(build_params_with || Grape.config.param_builder)
|
14
145
|
end
|
15
146
|
|
16
147
|
def params
|
17
|
-
@params ||=
|
18
|
-
rescue EOFError
|
19
|
-
raise Grape::Exceptions::EmptyMessageBody.new(content_type)
|
20
|
-
rescue Rack::Multipart::MultipartPartLimitError
|
21
|
-
raise Grape::Exceptions::TooManyMultipartFiles.new(Rack::Utils.multipart_part_limit)
|
148
|
+
@params ||= make_params
|
22
149
|
end
|
23
150
|
|
24
151
|
def headers
|
25
152
|
@headers ||= build_headers
|
26
153
|
end
|
27
154
|
|
28
|
-
|
155
|
+
def cookies
|
156
|
+
@cookies ||= Grape::Cookies.new(-> { rack_cookies })
|
157
|
+
end
|
29
158
|
|
159
|
+
# needs to be public until extensions param_builder are removed
|
30
160
|
def grape_routing_args
|
31
|
-
args = env[Grape::Env::GRAPE_ROUTING_ARGS].dup
|
32
161
|
# preserve version from query string parameters
|
33
|
-
|
34
|
-
args.delete(:route_info)
|
35
|
-
args
|
162
|
+
env[Grape::Env::GRAPE_ROUTING_ARGS]&.except(:version, :route_info) || {}
|
36
163
|
end
|
37
164
|
|
38
|
-
|
39
|
-
Grape::Util::LazyObject.new do
|
40
|
-
env.each_pair.with_object({}) do |(k, v), headers|
|
41
|
-
next unless k.to_s.start_with? HTTP_PREFIX
|
165
|
+
private
|
42
166
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
167
|
+
def make_params
|
168
|
+
@params_builder.call(rack_params).deep_merge!(grape_routing_args)
|
169
|
+
rescue EOFError
|
170
|
+
raise Grape::Exceptions::EmptyMessageBody.new(content_type)
|
171
|
+
rescue Rack::Multipart::MultipartPartLimitError, Rack::Multipart::MultipartTotalPartLimitError
|
172
|
+
raise Grape::Exceptions::TooManyMultipartFiles.new(Rack::Utils.multipart_part_limit)
|
173
|
+
rescue Rack::QueryParser::ParamsTooDeepError
|
174
|
+
raise Grape::Exceptions::TooDeepParameters.new(Rack::Utils.param_depth_limit)
|
175
|
+
rescue Rack::Utils::ParameterTypeError
|
176
|
+
raise Grape::Exceptions::ConflictingTypes
|
177
|
+
rescue Rack::Utils::InvalidParameterError
|
178
|
+
raise Grape::Exceptions::InvalidParameters
|
47
179
|
end
|
48
180
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
-header[5..].split('_').map(&:capitalize).join('-')
|
181
|
+
def build_headers
|
182
|
+
each_header.with_object(Grape::Util::Header.new) do |(k, v), headers|
|
183
|
+
next unless k.start_with? 'HTTP_'
|
184
|
+
|
185
|
+
transformed_header = KNOWN_HEADERS.fetch(k) { -k[5..].tr('_', '-').downcase }
|
186
|
+
headers[transformed_header] = v
|
56
187
|
end
|
57
188
|
end
|
58
189
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
class Router
|
5
|
+
class BaseRoute
|
6
|
+
delegate_missing_to :@options
|
7
|
+
|
8
|
+
attr_reader :index, :pattern, :options
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
@options = options.is_a?(ActiveSupport::OrderedOptions) ? options : ActiveSupport::OrderedOptions.new.update(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
alias attributes options
|
15
|
+
|
16
|
+
def regexp_capture_index
|
17
|
+
CaptureIndexCache[index]
|
18
|
+
end
|
19
|
+
|
20
|
+
def pattern_regexp
|
21
|
+
pattern.to_regexp
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_regexp(index)
|
25
|
+
@index = index
|
26
|
+
Regexp.new("(?<#{regexp_capture_index}>#{pattern_regexp})")
|
27
|
+
end
|
28
|
+
|
29
|
+
class CaptureIndexCache < Grape::Util::Cache
|
30
|
+
def initialize
|
31
|
+
super
|
32
|
+
@cache = Hash.new do |h, index|
|
33
|
+
h[index] = "_#{index}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Act like a Grape::Router::Route but for greedy_match
|
4
|
+
# see @neutral_map
|
5
|
+
|
6
|
+
module Grape
|
7
|
+
class Router
|
8
|
+
class GreedyRoute < BaseRoute
|
9
|
+
def initialize(pattern, options)
|
10
|
+
@pattern = pattern
|
11
|
+
super(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Grape::Router:Route defines params as a function
|
15
|
+
def params(_input = nil)
|
16
|
+
options[:params] || {}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/grape/router/pattern.rb
CHANGED
@@ -1,62 +1,76 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'forwardable'
|
4
|
-
require 'mustermann/grape'
|
5
|
-
require 'grape/util/cache'
|
6
|
-
|
7
3
|
module Grape
|
8
4
|
class Router
|
9
5
|
class Pattern
|
10
|
-
|
11
|
-
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
DEFAULT_CAPTURES = %w[format version].freeze
|
12
9
|
|
13
10
|
attr_reader :origin, :path, :pattern, :to_regexp
|
14
11
|
|
15
|
-
|
16
|
-
def_delegators :pattern, :named_captures, :params
|
12
|
+
def_delegators :pattern, :params
|
17
13
|
def_delegators :to_regexp, :===
|
18
14
|
alias match? ===
|
19
15
|
|
20
|
-
def initialize(
|
21
|
-
@origin
|
22
|
-
@path
|
23
|
-
@pattern =
|
16
|
+
def initialize(origin, suffix, options)
|
17
|
+
@origin = origin
|
18
|
+
@path = build_path(origin, options[:anchor], suffix)
|
19
|
+
@pattern = build_pattern(@path, options[:params], options[:format], options[:version], options[:requirements])
|
24
20
|
@to_regexp = @pattern.to_regexp
|
25
21
|
end
|
26
22
|
|
23
|
+
def captures_default
|
24
|
+
to_regexp.names
|
25
|
+
.delete_if { |n| DEFAULT_CAPTURES.include?(n) }
|
26
|
+
.to_h { |k| [k, ''] }
|
27
|
+
end
|
28
|
+
|
27
29
|
private
|
28
30
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
def build_pattern(path, params, format, version, requirements)
|
32
|
+
Mustermann::Grape.new(
|
33
|
+
path,
|
34
|
+
uri_decode: true,
|
35
|
+
params: params,
|
36
|
+
capture: extract_capture(format, version, requirements)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def build_path(pattern, anchor, suffix)
|
41
|
+
PatternCache[[build_path_from_pattern(pattern, anchor), suffix]]
|
34
42
|
end
|
35
43
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
pattern << '*path'
|
44
|
+
def extract_capture(format, version, requirements)
|
45
|
+
capture = {}.tap do |h|
|
46
|
+
h[:format] = map_str(format) if format.present?
|
47
|
+
h[:version] = map_str(version) if version.present?
|
41
48
|
end
|
42
49
|
|
43
|
-
|
44
|
-
parts[parts.length - 1] = "?#{parts.last}"
|
45
|
-
end.join('/') if pattern.end_with?('*path')
|
50
|
+
return capture if requirements.blank?
|
46
51
|
|
47
|
-
|
52
|
+
requirements.merge(capture)
|
48
53
|
end
|
49
54
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
+
def build_path_from_pattern(pattern, anchor)
|
56
|
+
if pattern.end_with?('*path')
|
57
|
+
pattern.dup.insert(pattern.rindex('/') + 1, '?')
|
58
|
+
elsif anchor
|
59
|
+
pattern
|
60
|
+
elsif pattern.end_with?('/')
|
61
|
+
"#{pattern}?*path"
|
62
|
+
else
|
63
|
+
"#{pattern}/?*path"
|
55
64
|
end
|
56
65
|
end
|
57
66
|
|
67
|
+
def map_str(value)
|
68
|
+
Array.wrap(value).map(&:to_s)
|
69
|
+
end
|
70
|
+
|
58
71
|
class PatternCache < Grape::Util::Cache
|
59
72
|
def initialize
|
73
|
+
super
|
60
74
|
@cache = Hash.new do |h, (pattern, suffix)|
|
61
75
|
h[[pattern, suffix]] = -"#{pattern}#{suffix}"
|
62
76
|
end
|