jsapi 3.0 → 3.1
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/lib/jsapi/controller/methods.rb +61 -59
- data/lib/jsapi/controller/response.rb +4 -3
- data/lib/jsapi/definition/content.rb +1 -2
- data/lib/jsapi/media/range.rb +1 -1
- data/lib/jsapi/media/type.rb +8 -9
- data/lib/jsapi/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c5ea7fc42be26ca35561f17cb2503e54efd9e138abd0ec4f9b7594fb27390ca
|
|
4
|
+
data.tar.gz: 1248e0b2499dd3616e5e4130fae88f9d5be8bd6a07e921317e86397a92832f71
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2f4af4e90d29a9b1df69ab71c5ad729eecd9d625286864c2dae078e2d6f6a43cab306fa9e999bccedeea82183bc8d5c3d4d6a977faf607fcb0236621eb3f19e2
|
|
7
|
+
data.tar.gz: 3b2467ea75b1c14bc99266977d7bff07ab74315178ea6d936795fc6fb1111a59d04bbd859b7ffb86bf478baca3d9e5eb4c4979f4b22c1e43f81bae5c981a36e1
|
|
@@ -117,34 +117,77 @@ module Jsapi
|
|
|
117
117
|
) if [nil, :empty, :nil].exclude?(omit)
|
|
118
118
|
|
|
119
119
|
operation = api.find_operation!(operation_name)
|
|
120
|
+
result = nil
|
|
120
121
|
response_definition = nil
|
|
121
122
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
bypassed = catch :bypass do
|
|
124
|
+
if result.nil?
|
|
125
|
+
# Authenticate request first if Authentication is included
|
|
126
|
+
if respond_to?(:_api_authenticated?, true)
|
|
127
|
+
raise Unauthorized unless _api_authenticated?(operation)
|
|
126
128
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
+
_api_callback(:after_authentication, operation_name)
|
|
130
|
+
end
|
|
129
131
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
+
status = Status::Code.from(status)
|
|
133
|
+
response_definition = operation.find_response_for!(status)
|
|
132
134
|
|
|
133
|
-
|
|
135
|
+
api_params = _api_params(operation, strong: strong)
|
|
134
136
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
+
if bang
|
|
138
|
+
raise ParametersInvalid.new(api_params) if api_params.invalid?
|
|
137
139
|
|
|
138
|
-
|
|
140
|
+
_api_callback(:after_validation, operation_name, api_params)
|
|
141
|
+
end
|
|
142
|
+
result = block&.call(api_params)
|
|
143
|
+
break if performed?
|
|
139
144
|
end
|
|
140
145
|
|
|
141
|
-
|
|
146
|
+
# Produce response
|
|
147
|
+
media_type, content_definition =
|
|
148
|
+
response_definition
|
|
149
|
+
.media_type_and_content_for(*_api_accept)
|
|
150
|
+
|
|
151
|
+
status_code = status&.to_i
|
|
152
|
+
head(status_code) && break unless content_definition
|
|
153
|
+
|
|
154
|
+
content_type = media_type.to_s
|
|
155
|
+
result = _api_before_rendering(operation_name, result, api_params)
|
|
156
|
+
|
|
157
|
+
if (json_media_type = media_type.json?) || media_type.sequential_json?
|
|
158
|
+
api_response = Response.new(
|
|
159
|
+
result,
|
|
160
|
+
content_definition,
|
|
161
|
+
omit: omit,
|
|
162
|
+
locale: response_definition.locale
|
|
163
|
+
)
|
|
164
|
+
if json_media_type
|
|
165
|
+
render(json: api_response, status: status_code, content_type: content_type)
|
|
166
|
+
else
|
|
167
|
+
self.content_type = content_type
|
|
168
|
+
response.status = status_code
|
|
169
|
+
begin
|
|
170
|
+
response.stream.tap do |stream|
|
|
171
|
+
api_response.write_seq_json_to(stream, media_type)
|
|
172
|
+
ensure
|
|
173
|
+
stream.close
|
|
174
|
+
end
|
|
175
|
+
rescue StandardError => e
|
|
176
|
+
throw :bypass, e
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
elsif media_type == Media::Type::TEXT_PLAIN
|
|
180
|
+
render(plain: result.to_s, status: status_code, content_type: content_type)
|
|
181
|
+
end
|
|
182
|
+
nil
|
|
142
183
|
rescue StandardError => e
|
|
143
|
-
|
|
184
|
+
raise e if result.is_a?(Error)
|
|
185
|
+
|
|
186
|
+
# Get rescue handler for the error
|
|
144
187
|
rescue_handler = api.rescue_handler_for(e)
|
|
145
188
|
raise e if rescue_handler.nil?
|
|
146
189
|
|
|
147
|
-
#
|
|
190
|
+
# Set error status code and response definition
|
|
148
191
|
status = rescue_handler.status_code
|
|
149
192
|
response_definition = operation.find_response_for(status)
|
|
150
193
|
raise e if response_definition.nil?
|
|
@@ -154,51 +197,10 @@ module Jsapi
|
|
|
154
197
|
callback.respond_to?(:call) ? callback.call(e) : send(callback, e)
|
|
155
198
|
end
|
|
156
199
|
|
|
157
|
-
Error.new(e, status: status)
|
|
158
|
-
|
|
159
|
-
# Return if response body has already been rendered
|
|
160
|
-
return if response_body
|
|
161
|
-
|
|
162
|
-
# Produce response
|
|
163
|
-
media_type, content_definition =
|
|
164
|
-
response_definition
|
|
165
|
-
.media_type_and_content_for(*_api_accept)
|
|
166
|
-
|
|
167
|
-
status = status&.to_i
|
|
168
|
-
return head(status) unless content_definition
|
|
169
|
-
|
|
170
|
-
result = _api_before_rendering(operation_name, result, api_params)
|
|
171
|
-
|
|
172
|
-
if media_type == Media::Type::TEXT_PLAIN
|
|
173
|
-
render(
|
|
174
|
-
plain: result.to_s,
|
|
175
|
-
status: status,
|
|
176
|
-
content_type: media_type.to_s
|
|
177
|
-
)
|
|
178
|
-
elsif media_type.json? || media_type.json_seq?
|
|
179
|
-
api_response = Response.new(
|
|
180
|
-
result,
|
|
181
|
-
content_definition,
|
|
182
|
-
omit: omit,
|
|
183
|
-
locale: response_definition.locale
|
|
184
|
-
)
|
|
185
|
-
if media_type.json?
|
|
186
|
-
render(
|
|
187
|
-
json: api_response,
|
|
188
|
-
status: status,
|
|
189
|
-
content_type: media_type.to_s
|
|
190
|
-
)
|
|
191
|
-
else
|
|
192
|
-
self.content_type = media_type.to_s
|
|
193
|
-
response.status = status
|
|
194
|
-
|
|
195
|
-
response.stream.tap do |stream|
|
|
196
|
-
api_response.write_json_seq_to(stream)
|
|
197
|
-
ensure
|
|
198
|
-
stream.close
|
|
199
|
-
end
|
|
200
|
-
end
|
|
200
|
+
result = Error.new(e, status: status)
|
|
201
|
+
retry
|
|
201
202
|
end
|
|
203
|
+
raise bypassed if bypassed.is_a?(Exception)
|
|
202
204
|
end
|
|
203
205
|
end
|
|
204
206
|
|
|
@@ -41,8 +41,9 @@ module Jsapi
|
|
|
41
41
|
as_json.to_json
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
# Writes the response
|
|
45
|
-
def
|
|
44
|
+
# Writes the response as sequential \JSON to +stream+.
|
|
45
|
+
def write_seq_json_to(stream, media_type = nil)
|
|
46
|
+
record_separator = "\u001E" if media_type&.subtype == 'json-seq' # see RFC 7464
|
|
46
47
|
schema = @content_definition.schema
|
|
47
48
|
object = @object
|
|
48
49
|
object = schema.default_value(context: :response) if object.nil?
|
|
@@ -56,7 +57,7 @@ module Jsapi
|
|
|
56
57
|
end
|
|
57
58
|
|
|
58
59
|
items.each_with_index do |item, index|
|
|
59
|
-
stream.write(
|
|
60
|
+
stream.write(record_separator) if record_separator
|
|
60
61
|
stream.write(
|
|
61
62
|
item_schema.jsonify(
|
|
62
63
|
item,
|
|
@@ -51,8 +51,7 @@ module Jsapi
|
|
|
51
51
|
example_builder = nil
|
|
52
52
|
|
|
53
53
|
with_openapi_extensions(
|
|
54
|
-
**if
|
|
55
|
-
schema.array? && version >= OpenAPI::V3_2
|
|
54
|
+
**if version >= OpenAPI::V3_2 && media_type&.sequential_json? && schema.array?
|
|
56
55
|
{ itemSchema: schema.items.to_openapi(version) }
|
|
57
56
|
else
|
|
58
57
|
{ schema: schema.to_openapi(version) }
|
data/lib/jsapi/media/range.rb
CHANGED
|
@@ -18,7 +18,7 @@ module Jsapi
|
|
|
18
18
|
class << self
|
|
19
19
|
# Transforms +value+ to an instance of this class.
|
|
20
20
|
#
|
|
21
|
-
# Raises an +ArgumentError+
|
|
21
|
+
# Raises an +ArgumentError+ if +value+ can not be transformed to a Media::Range.
|
|
22
22
|
def from(value)
|
|
23
23
|
media_range = try_from(value)
|
|
24
24
|
return media_range unless media_range.nil?
|
data/lib/jsapi/media/type.rb
CHANGED
|
@@ -12,16 +12,15 @@ module Jsapi
|
|
|
12
12
|
# Media::Type for <code>"application/json"</code>.
|
|
13
13
|
APPLICATION_JSON = Type.new('application', 'json')
|
|
14
14
|
|
|
15
|
-
# Media::Type for <code>"application/json-seq"</code>.
|
|
16
|
-
APPLICATION_JSON_SEQ = Type.new('application', 'json-seq')
|
|
17
|
-
|
|
18
15
|
# Media::Type for <code>"text/plain"</code>.
|
|
19
16
|
TEXT_PLAIN = Type.new('text', 'plain')
|
|
20
17
|
|
|
18
|
+
SEQ_JSON_SUBTYPE = /\A(jsonl|(|.+\+)json-seq|x-ndjson)\Z/.freeze # :nodoc:
|
|
19
|
+
|
|
21
20
|
class << self
|
|
22
21
|
# Transforms +value+ to an instance of this class.
|
|
23
22
|
#
|
|
24
|
-
# Raises an ArgumentError
|
|
23
|
+
# Raises an ArgumentError if +value+ can not be transformed to a Media::Type.
|
|
25
24
|
def from(value)
|
|
26
25
|
media_type = try_from(value)
|
|
27
26
|
return media_type unless media_type.nil?
|
|
@@ -31,7 +30,7 @@ module Jsapi
|
|
|
31
30
|
|
|
32
31
|
# Tries to transform +value+ to an instance of this class.
|
|
33
32
|
#
|
|
34
|
-
# Returns nil if +value+
|
|
33
|
+
# Returns nil if +value+ can not be transformed to a Media::Type.
|
|
35
34
|
def try_from(value)
|
|
36
35
|
return value if value.is_a?(Type)
|
|
37
36
|
|
|
@@ -59,16 +58,16 @@ module Jsapi
|
|
|
59
58
|
subtype <=> other.subtype
|
|
60
59
|
end
|
|
61
60
|
|
|
62
|
-
# Returns true if it represents a JSON media type as specified by
|
|
61
|
+
# Returns true if it represents a \JSON media type as specified by
|
|
63
62
|
# https://mimesniff.spec.whatwg.org/#json-mime-type.
|
|
64
63
|
def json?
|
|
65
64
|
(type.in?(%w[application text]) && subtype == 'json') ||
|
|
66
65
|
subtype.end_with?('+json')
|
|
67
66
|
end
|
|
68
67
|
|
|
69
|
-
# Returns true if it
|
|
70
|
-
def
|
|
71
|
-
type == 'application' && subtype
|
|
68
|
+
# Returns true if it represents a sequential \JSON media type.
|
|
69
|
+
def sequential_json?
|
|
70
|
+
type == 'application' && SEQ_JSON_SUBTYPE.match?(subtype)
|
|
72
71
|
end
|
|
73
72
|
end
|
|
74
73
|
end
|
data/lib/jsapi/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: jsapi
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '3.
|
|
4
|
+
version: '3.1'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Denis Göller
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description:
|
|
14
14
|
email: denis@dmgoeller.de
|