jsapi 1.4 → 1.4.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 +72 -96
- data/lib/jsapi/media/range.rb +69 -0
- data/lib/jsapi/media/type.rb +66 -0
- data/lib/jsapi/media/type_and_subtype.rb +38 -0
- data/lib/jsapi/media.rb +4 -0
- data/lib/jsapi/meta/definitions.rb +11 -15
- data/lib/jsapi/meta/existence.rb +3 -1
- data/lib/jsapi/meta/openapi/version.rb +16 -4
- data/lib/jsapi/meta/operation.rb +3 -3
- data/lib/jsapi/meta/parameter/base.rb +1 -1
- data/lib/jsapi/meta/pathname.rb +3 -3
- data/lib/jsapi/meta/response/base.rb +6 -19
- data/lib/jsapi/meta/schema/boundary.rb +1 -0
- data/lib/jsapi/version.rb +1 -1
- data/lib/jsapi.rb +1 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7651bda7e379186840e78ede1870f022b69deca559b6ba5ad6d0cbc8aac5c840
|
|
4
|
+
data.tar.gz: 16a661d4c24e1195f23d6fa0a23d27ba53fb944819b2f9a57c2174456f5ca913
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0e1eebb7f9d53a3e2f28a562edac148093b506ade987384e093530f5d337b85a5aabeb5acae70ca80233f75215e1dbc158b4a786724a8eb77670e63ee0be348d
|
|
7
|
+
data.tar.gz: 51d183148b0575ba9d437c2d3208257ab6e0b1cdec9d3024aa63a6261a56542e9bee8907acc4bb5f042360f90114bf668f1e46836e97dcf1332d30b616f8d264
|
|
@@ -12,12 +12,16 @@ module Jsapi
|
|
|
12
12
|
self.class.api_definitions
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
##
|
|
16
|
+
# :method: api_operation
|
|
17
|
+
# :args: operation_name = nil, omit: nil, status: nil, strong: false, &block
|
|
18
|
+
#
|
|
15
19
|
# Performs an API operation by calling the given block. The request parameters are
|
|
16
20
|
# passed as an instance of the operation's model class to the block. The object
|
|
17
21
|
# returned by the block is implicitly rendered according to the appropriate +response+
|
|
18
|
-
# specification when the content type is a JSON MIME type. When content type is
|
|
22
|
+
# specification when the content type is a \JSON MIME type. When content type is
|
|
19
23
|
# <code>application/json-seq</code>, the object returned by the block is streamed in
|
|
20
|
-
# JSON sequence text format.
|
|
24
|
+
# \JSON sequence text format.
|
|
21
25
|
#
|
|
22
26
|
# api_operation('foo') do |api_params|
|
|
23
27
|
# # ...
|
|
@@ -36,41 +40,68 @@ module Jsapi
|
|
|
36
40
|
# - +:nil+ - All of the properties whose value is +nil+ are omitted.
|
|
37
41
|
#
|
|
38
42
|
# Raises an +ArgumentError+ when +:omit+ is other than +:empty+, +:nil+ or +nil+.
|
|
39
|
-
def api_operation(operation_name = nil,
|
|
40
|
-
omit: nil,
|
|
41
|
-
status: nil,
|
|
42
|
-
strong: false,
|
|
43
|
-
&block)
|
|
44
|
-
_api_operation(
|
|
45
|
-
operation_name,
|
|
46
|
-
bang: false,
|
|
47
|
-
omit: omit,
|
|
48
|
-
status: status,
|
|
49
|
-
strong: strong,
|
|
50
|
-
&block
|
|
51
|
-
)
|
|
52
|
-
end
|
|
53
43
|
|
|
54
|
-
|
|
55
|
-
#
|
|
44
|
+
##
|
|
45
|
+
# :method: api_operation!
|
|
46
|
+
# :args: operation_name = nil, omit: nil, status: nil, strong: false, &block
|
|
47
|
+
#
|
|
48
|
+
# Like +api_operation+, except that a ParametersInvalid exception is raised
|
|
49
|
+
# when request parameters are invalid.
|
|
56
50
|
#
|
|
57
51
|
# api_operation!('foo') do |api_params|
|
|
58
52
|
# # ...
|
|
59
53
|
# end
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
54
|
+
|
|
55
|
+
[true, false].each do |bang|
|
|
56
|
+
define_method(bang ? :api_operation! : :api_operation) \
|
|
57
|
+
do |operation_name = nil, omit: nil, status: nil, strong: false, &block|
|
|
58
|
+
definitions = api_definitions
|
|
59
|
+
operation_model = _find_api_operation_model(operation_name, definitions)
|
|
60
|
+
response_model = _find_api_response_model(operation_model, status, definitions)
|
|
61
|
+
head(status) && return unless block
|
|
62
|
+
|
|
63
|
+
# Perform operation
|
|
64
|
+
api_params = _api_params(operation_model, definitions, strong: strong)
|
|
65
|
+
api_response = Response.new(
|
|
66
|
+
begin
|
|
67
|
+
raise ParametersInvalid.new(api_params) if bang && api_params.invalid?
|
|
68
|
+
|
|
69
|
+
block.call(api_params)
|
|
70
|
+
rescue StandardError => e
|
|
71
|
+
# Lookup a rescue handler
|
|
72
|
+
rescue_handler = definitions.rescue_handler_for(e)
|
|
73
|
+
raise e if rescue_handler.nil?
|
|
74
|
+
|
|
75
|
+
# Change the HTTP status code and response model
|
|
76
|
+
status = rescue_handler.status
|
|
77
|
+
response_model = operation_model.response(status)&.resolve(definitions)
|
|
78
|
+
raise e if response_model.nil?
|
|
79
|
+
|
|
80
|
+
# Call on_rescue callbacks
|
|
81
|
+
definitions.on_rescue_callbacks.each do |callback|
|
|
82
|
+
callback.respond_to?(:call) ? callback.call(e) : send(callback, e)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
Error.new(e, status: status)
|
|
86
|
+
end,
|
|
87
|
+
response_model, definitions, omit: omit
|
|
88
|
+
)
|
|
89
|
+
# Write response
|
|
90
|
+
media_type = response_model.content_type
|
|
91
|
+
|
|
92
|
+
if media_type == Media::Type::APPLICATION_JSON_SEQ
|
|
93
|
+
self.content_type = media_type.to_s
|
|
94
|
+
response.status = status
|
|
95
|
+
|
|
96
|
+
response.stream.tap do |stream|
|
|
97
|
+
api_response.write_json_seq_to(stream)
|
|
98
|
+
ensure
|
|
99
|
+
stream.close
|
|
100
|
+
end
|
|
101
|
+
elsif media_type.json?
|
|
102
|
+
render(json: api_response, status: status, content_type: media_type.to_s)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
74
105
|
end
|
|
75
106
|
|
|
76
107
|
# Returns the request parameters as an instance of the operation's model class.
|
|
@@ -88,7 +119,7 @@ module Jsapi
|
|
|
88
119
|
def api_params(operation_name = nil, strong: false)
|
|
89
120
|
definitions = api_definitions
|
|
90
121
|
_api_params(
|
|
91
|
-
|
|
122
|
+
_find_api_operation_model(operation_name, definitions),
|
|
92
123
|
definitions,
|
|
93
124
|
strong: strong
|
|
94
125
|
)
|
|
@@ -110,89 +141,34 @@ module Jsapi
|
|
|
110
141
|
# Raises an +ArgumentError+ when +:omit+ is other than +:empty+, +:nil+ or +nil+.
|
|
111
142
|
def api_response(result, operation_name = nil, omit: nil, status: nil)
|
|
112
143
|
definitions = api_definitions
|
|
113
|
-
|
|
114
|
-
response_model =
|
|
144
|
+
operation_model = _find_api_operation_model(operation_name, definitions)
|
|
145
|
+
response_model = _find_api_response_model(operation_model, status, definitions)
|
|
115
146
|
|
|
116
|
-
Response.new(result, response_model,
|
|
147
|
+
Response.new(result, response_model, definitions, omit: omit)
|
|
117
148
|
end
|
|
118
149
|
|
|
119
150
|
private
|
|
120
151
|
|
|
121
|
-
def
|
|
122
|
-
|
|
123
|
-
operation = _find_api_operation(operation_name, definitions)
|
|
124
|
-
|
|
125
|
-
# Perform operation
|
|
126
|
-
response_model = _api_response(operation, status, definitions)
|
|
127
|
-
head(status) && return unless block
|
|
128
|
-
|
|
129
|
-
params = _api_params(operation, definitions, strong: strong)
|
|
130
|
-
|
|
131
|
-
result = begin
|
|
132
|
-
raise ParametersInvalid.new(params) if bang && params.invalid?
|
|
133
|
-
|
|
134
|
-
block.call(params)
|
|
135
|
-
rescue StandardError => e
|
|
136
|
-
# Lookup a rescue handler
|
|
137
|
-
rescue_handler = definitions.rescue_handler_for(e)
|
|
138
|
-
raise e if rescue_handler.nil?
|
|
139
|
-
|
|
140
|
-
# Change the HTTP status code and response model
|
|
141
|
-
status = rescue_handler.status
|
|
142
|
-
response_model = operation.response(status)&.resolve(definitions)
|
|
143
|
-
raise e if response_model.nil?
|
|
144
|
-
|
|
145
|
-
# Call on_rescue callbacks
|
|
146
|
-
definitions.on_rescue_callbacks.each do |callback|
|
|
147
|
-
if callback.respond_to?(:call)
|
|
148
|
-
callback.call(e)
|
|
149
|
-
else
|
|
150
|
-
send(callback, e)
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
Error.new(e, status: status)
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
# Write response
|
|
158
|
-
return unless response_model.json_type? || response_model.json_seq_type?
|
|
159
|
-
|
|
160
|
-
response = Response.new(result, response_model, definitions, omit: omit)
|
|
161
|
-
self.content_type = response_model.content_type
|
|
162
|
-
|
|
163
|
-
if response_model.json_seq_type?
|
|
164
|
-
self.response.status = status
|
|
165
|
-
|
|
166
|
-
self.response.stream.tap do |stream|
|
|
167
|
-
response.write_json_seq_to(stream)
|
|
168
|
-
ensure
|
|
169
|
-
stream.close
|
|
170
|
-
end
|
|
171
|
-
else
|
|
172
|
-
render(json: response, status: status)
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def _api_params(operation, definitions, strong:)
|
|
177
|
-
(operation.model || Model::Base).new(
|
|
152
|
+
def _api_params(operation_model, definitions, strong:)
|
|
153
|
+
(operation_model.model || Model::Base).new(
|
|
178
154
|
Parameters.new(
|
|
179
155
|
params.except(:action, :controller, :format).permit!,
|
|
180
156
|
request,
|
|
181
|
-
|
|
157
|
+
operation_model,
|
|
182
158
|
definitions,
|
|
183
159
|
strong: strong
|
|
184
160
|
)
|
|
185
161
|
)
|
|
186
162
|
end
|
|
187
163
|
|
|
188
|
-
def
|
|
164
|
+
def _find_api_response_model(operation, status, definitions)
|
|
189
165
|
response = operation.response(status)
|
|
190
166
|
return response.resolve(definitions) if response
|
|
191
167
|
|
|
192
168
|
raise "status code not defined: #{status}"
|
|
193
169
|
end
|
|
194
170
|
|
|
195
|
-
def
|
|
171
|
+
def _find_api_operation_model(operation_name, definitions)
|
|
196
172
|
operation = definitions.find_operation(operation_name)
|
|
197
173
|
return operation if operation
|
|
198
174
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'type_and_subtype'
|
|
4
|
+
|
|
5
|
+
module Jsapi
|
|
6
|
+
module Media
|
|
7
|
+
# Represents a media range.
|
|
8
|
+
class Range
|
|
9
|
+
include Comparable
|
|
10
|
+
include TypeAndSubtype
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
# Transforms +value+ to an instance of this class.
|
|
14
|
+
#
|
|
15
|
+
# Raises an ArgumentError when +value+ could not be transformed.
|
|
16
|
+
def from(value)
|
|
17
|
+
media_range = try_from(value)
|
|
18
|
+
return media_range unless media_range.nil?
|
|
19
|
+
|
|
20
|
+
raise ArgumentError, "invalid media range: #{value.inspect}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Tries to transform +value+ to an instance of this class. Returns nil
|
|
24
|
+
# if +value+ could not be transformed.
|
|
25
|
+
def try_from(value)
|
|
26
|
+
return value if value.is_a?(Range)
|
|
27
|
+
|
|
28
|
+
type_and_subtype = pattern.match(value.to_s)&.captures
|
|
29
|
+
new(*type_and_subtype) if type_and_subtype&.count == 2
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def pattern
|
|
35
|
+
@pattern ||= begin
|
|
36
|
+
name = '[0-9a-zA-Z-]+'
|
|
37
|
+
%r{(\*|#{name})/(\*|(?:#{name}(?:\.#{name})?(?:\+#{name})?))}.freeze
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Compares it with +other+ by +priority+.
|
|
43
|
+
def <=>(other)
|
|
44
|
+
return unless other.is_a?(self.class)
|
|
45
|
+
|
|
46
|
+
result = priority <=> other.priority
|
|
47
|
+
return result unless result.zero?
|
|
48
|
+
|
|
49
|
+
result = type <=> other.type
|
|
50
|
+
return result unless result.zero?
|
|
51
|
+
|
|
52
|
+
subtype <=> other.subtype
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Returns true if the given media type matches the media range.
|
|
56
|
+
def match?(media_type)
|
|
57
|
+
media_type = Type.from(media_type) unless media_type.nil?
|
|
58
|
+
|
|
59
|
+
(type == '*' || type == media_type&.type) &&
|
|
60
|
+
(subtype == '*' || subtype == media_type&.subtype)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Returns the level of priority of the media range.
|
|
64
|
+
def priority
|
|
65
|
+
@priority ||= (type == '*' ? 2 : 0) + (subtype == '*' ? 1 : 0) + 1
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'type_and_subtype'
|
|
4
|
+
|
|
5
|
+
module Jsapi
|
|
6
|
+
module Media
|
|
7
|
+
# Represents a media type.
|
|
8
|
+
class Type
|
|
9
|
+
include Comparable
|
|
10
|
+
include TypeAndSubtype
|
|
11
|
+
|
|
12
|
+
# The <code>"application/json"</code> media type.
|
|
13
|
+
APPLICATION_JSON = Type.new('application', 'json')
|
|
14
|
+
|
|
15
|
+
# The <code>"application/json-seq"</code> media type.
|
|
16
|
+
APPLICATION_JSON_SEQ = Type.new('application', 'json-seq')
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
# Transforms +value+ to an instance of this class.
|
|
20
|
+
#
|
|
21
|
+
# Raises an ArgumentError when +value+ could not be transformed.
|
|
22
|
+
def from(value)
|
|
23
|
+
media_type = try_from(value)
|
|
24
|
+
return media_type unless media_type.nil?
|
|
25
|
+
|
|
26
|
+
raise ArgumentError, "invalid media type: #{value.inspect}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Tries to transform +value+ to an instance of this class. Returns nil
|
|
30
|
+
# if +value+ could not be transformed.
|
|
31
|
+
def try_from(value)
|
|
32
|
+
return value if value.is_a?(Type)
|
|
33
|
+
|
|
34
|
+
type_and_subtype = pattern.match(value.to_s)&.captures
|
|
35
|
+
new(*type_and_subtype) if type_and_subtype&.count == 2
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def pattern
|
|
41
|
+
@pattern ||= begin
|
|
42
|
+
name = '[0-9a-zA-Z-]+'
|
|
43
|
+
%r{(#{name})/(#{name}(?:\.#{name})?(?:\+#{name})?)}.freeze
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Compares it with +other+ by +type+ and +subtype+.
|
|
49
|
+
def <=>(other)
|
|
50
|
+
return unless other.is_a?(self.class)
|
|
51
|
+
|
|
52
|
+
result = type <=> other.type
|
|
53
|
+
return result unless result.zero?
|
|
54
|
+
|
|
55
|
+
subtype <=> other.subtype
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Returns true if it represents a JSON media type as specified by
|
|
59
|
+
# https://mimesniff.spec.whatwg.org/#json-mime-type.
|
|
60
|
+
def json?
|
|
61
|
+
(type.in?(%w[application text]) && subtype == 'json') ||
|
|
62
|
+
subtype.end_with?('+json')
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jsapi
|
|
4
|
+
module Media
|
|
5
|
+
module TypeAndSubtype # :nodoc:
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.attr_reader :type, :subtype
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(type, subtype)
|
|
11
|
+
@type = type.downcase
|
|
12
|
+
@subtype = subtype.downcase
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ==(other)
|
|
16
|
+
other.is_a?(self.class) &&
|
|
17
|
+
type == other.type &&
|
|
18
|
+
subtype == other.subtype
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
alias eql? ==
|
|
22
|
+
|
|
23
|
+
def hash
|
|
24
|
+
@hash ||= [type, subtype].hash
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def inspect
|
|
28
|
+
"#<#{self.class} #{to_s.inspect}>"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
@to_s ||= "#{type}/#{subtype}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
alias as_json to_s
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/jsapi/media.rb
ADDED
|
@@ -266,17 +266,18 @@ module Jsapi
|
|
|
266
266
|
]
|
|
267
267
|
end.presence
|
|
268
268
|
|
|
269
|
-
openapi_objects =
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
269
|
+
openapi_objects = (
|
|
270
|
+
%i[external_docs info parameters responses schemas
|
|
271
|
+
security_requirements security_schemes tags] +
|
|
272
|
+
if version == OpenAPI::V2_0
|
|
273
|
+
%i[base_path host schemes]
|
|
273
274
|
else
|
|
274
|
-
%i[callbacks examples
|
|
275
|
-
|
|
276
|
-
|
|
275
|
+
%i[callbacks examples headers links request_bodies servers]
|
|
276
|
+
end
|
|
277
|
+
).index_with { |key| object_to_openapi(objects[key], version).presence }
|
|
277
278
|
|
|
278
279
|
with_openapi_extensions(
|
|
279
|
-
if version
|
|
280
|
+
if version == OpenAPI::V2_0
|
|
280
281
|
openapi_server = objects[:servers].first || default_server
|
|
281
282
|
uri = URI(openapi_server.url) if openapi_server
|
|
282
283
|
{
|
|
@@ -290,7 +291,7 @@ module Jsapi
|
|
|
290
291
|
operation.consumes(self)
|
|
291
292
|
end.uniq.sort.presence,
|
|
292
293
|
produces: operations.flat_map do |operation|
|
|
293
|
-
operation.produces(self)
|
|
294
|
+
operation.produces(self).map(&:to_s)
|
|
294
295
|
end.uniq.sort.presence,
|
|
295
296
|
paths: openapi_paths,
|
|
296
297
|
definitions: openapi_objects[:schemas],
|
|
@@ -301,12 +302,7 @@ module Jsapi
|
|
|
301
302
|
else
|
|
302
303
|
{
|
|
303
304
|
# Order according to the OpenAPI specification 3.x
|
|
304
|
-
openapi:
|
|
305
|
-
case version.minor
|
|
306
|
-
when 0 then '3.0.3'
|
|
307
|
-
when 1 then '3.1.1'
|
|
308
|
-
when 2 then '3.2.0'
|
|
309
|
-
end,
|
|
305
|
+
openapi: version.to_s,
|
|
310
306
|
info: openapi_objects[:info],
|
|
311
307
|
servers:
|
|
312
308
|
openapi_objects[:servers] ||
|
data/lib/jsapi/meta/existence.rb
CHANGED
|
@@ -30,7 +30,9 @@ module Jsapi
|
|
|
30
30
|
# or must be +false+.
|
|
31
31
|
PRESENT = new(4)
|
|
32
32
|
|
|
33
|
-
#
|
|
33
|
+
# Transforms +value+ to an instance of this class.
|
|
34
|
+
#
|
|
35
|
+
# Raises an +ArgumentError+ if +value+ could not be transformed.
|
|
34
36
|
def self.from(value)
|
|
35
37
|
return value if value.is_a?(Existence)
|
|
36
38
|
|
|
@@ -6,9 +6,9 @@ module Jsapi
|
|
|
6
6
|
class Version
|
|
7
7
|
include Comparable
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
# Transforms +version+ to an instance of this class.
|
|
10
10
|
#
|
|
11
|
-
# Raises an +ArgumentError+ if +version+
|
|
11
|
+
# Raises an +ArgumentError+ if +version+ could not be transformed.
|
|
12
12
|
def self.from(version)
|
|
13
13
|
return version if version.is_a?(Version)
|
|
14
14
|
|
|
@@ -48,13 +48,25 @@ module Jsapi
|
|
|
48
48
|
minor <=> other.minor
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
def inspect
|
|
51
|
+
def inspect # :nodoc:
|
|
52
52
|
"<#{self.class.name} #{self}>"
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def to_s # :nodoc:
|
|
56
|
-
|
|
56
|
+
@to_s ||=
|
|
57
|
+
case [major, minor]
|
|
58
|
+
when [3, 0]
|
|
59
|
+
'3.0.3'
|
|
60
|
+
when [3, 1]
|
|
61
|
+
'3.1.1'
|
|
62
|
+
when [3, 2]
|
|
63
|
+
'3.2.0'
|
|
64
|
+
else
|
|
65
|
+
"#{major}.#{minor}"
|
|
66
|
+
end
|
|
57
67
|
end
|
|
68
|
+
|
|
69
|
+
alias as_json to_s
|
|
58
70
|
end
|
|
59
71
|
end
|
|
60
72
|
end
|
data/lib/jsapi/meta/operation.rb
CHANGED
|
@@ -117,12 +117,12 @@ module Jsapi
|
|
|
117
117
|
parent_path + path
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
-
# Returns the
|
|
120
|
+
# Returns the media type consumed by the operation.
|
|
121
121
|
def consumes(definitions)
|
|
122
122
|
request_body&.resolve(definitions)&.content_type
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
-
# Returns an array containing the
|
|
125
|
+
# Returns an array containing the media types produced by the operation.
|
|
126
126
|
def produces(definitions)
|
|
127
127
|
responses.values.filter_map do |response|
|
|
128
128
|
response.resolve(definitions).content_type
|
|
@@ -154,7 +154,7 @@ module Jsapi
|
|
|
154
154
|
result[:consumes] = [consumes]
|
|
155
155
|
end
|
|
156
156
|
if (produces = produces(definitions)).present?
|
|
157
|
-
result[:produces] = produces
|
|
157
|
+
result[:produces] = produces.map(&:to_s)
|
|
158
158
|
end
|
|
159
159
|
result[:schemes] = schemes if schemes.present?
|
|
160
160
|
elsif servers.present?
|
|
@@ -11,7 +11,7 @@ module Jsapi
|
|
|
11
11
|
|
|
12
12
|
##
|
|
13
13
|
# :attr: content_type
|
|
14
|
-
# The
|
|
14
|
+
# The media type used to describe complex parameters in \OpenAPI 3.0 and higher.
|
|
15
15
|
attribute :content_type, String
|
|
16
16
|
|
|
17
17
|
##
|
data/lib/jsapi/meta/pathname.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Jsapi
|
|
|
5
5
|
# Represents a relative path name.
|
|
6
6
|
class Pathname
|
|
7
7
|
class << self
|
|
8
|
-
#
|
|
8
|
+
# Transforms +name+ to an instance of this class.
|
|
9
9
|
def from(name)
|
|
10
10
|
return name if name.is_a?(Pathname)
|
|
11
11
|
|
|
@@ -30,8 +30,8 @@ module Jsapi
|
|
|
30
30
|
|
|
31
31
|
alias eql? ==
|
|
32
32
|
|
|
33
|
-
# Creates a new Pathname by appending +other+ to
|
|
34
|
-
# Returns
|
|
33
|
+
# Creates a new Pathname by appending +other+ to itself.
|
|
34
|
+
# Returns itself if +other+ is nil.
|
|
35
35
|
def +(other)
|
|
36
36
|
return self if other.nil?
|
|
37
37
|
|
|
@@ -7,15 +7,12 @@ module Jsapi
|
|
|
7
7
|
class Base < Model::Base
|
|
8
8
|
include OpenAPI::Extensions
|
|
9
9
|
|
|
10
|
-
JSON_TYPE = %r{(^application/|^text/|\+)json$}.freeze # :nodoc:
|
|
11
|
-
JSON_SEQ_TYPE = 'application/json-seq' # :nodoc:
|
|
12
|
-
|
|
13
10
|
delegate_missing_to :schema
|
|
14
11
|
|
|
15
12
|
##
|
|
16
13
|
# :attr: content_type
|
|
17
|
-
# The
|
|
18
|
-
attribute :content_type,
|
|
14
|
+
# The media type of the response, <code>"application/json"</code> by default.
|
|
15
|
+
attribute :content_type, Media::Type, default: Media::Type::APPLICATION_JSON
|
|
19
16
|
|
|
20
17
|
##
|
|
21
18
|
# :attr: description
|
|
@@ -66,17 +63,6 @@ module Jsapi
|
|
|
66
63
|
@schema = Schema.new(keywords)
|
|
67
64
|
end
|
|
68
65
|
|
|
69
|
-
# Returns true if content type is a JSON MIME type as specified by
|
|
70
|
-
# https://mimesniff.spec.whatwg.org/#json-mime-type.
|
|
71
|
-
def json_type?
|
|
72
|
-
content_type.match?(JSON_TYPE)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Returns true if content type is <code>"application/json-seq"</code>.
|
|
76
|
-
def json_seq_type?
|
|
77
|
-
content_type == JSON_SEQ_TYPE
|
|
78
|
-
end
|
|
79
|
-
|
|
80
66
|
# Returns a hash representing the \OpenAPI response object.
|
|
81
67
|
def to_openapi(version, definitions)
|
|
82
68
|
version = OpenAPI::Version.from(version)
|
|
@@ -91,7 +77,7 @@ module Jsapi
|
|
|
91
77
|
end.compact.presence,
|
|
92
78
|
examples: (
|
|
93
79
|
if (example = examples.values.first).present?
|
|
94
|
-
{ content_type => example.resolve(definitions).value }
|
|
80
|
+
{ content_type.to_s => example.resolve(definitions).value }
|
|
95
81
|
end
|
|
96
82
|
)
|
|
97
83
|
}
|
|
@@ -103,8 +89,9 @@ module Jsapi
|
|
|
103
89
|
header.to_openapi(version)
|
|
104
90
|
end.presence,
|
|
105
91
|
content: {
|
|
106
|
-
content_type => {
|
|
107
|
-
**if
|
|
92
|
+
content_type.to_s => {
|
|
93
|
+
**if content_type == Media::Type::APPLICATION_JSON_SEQ &&
|
|
94
|
+
schema.array? && version >= OpenAPI::V3_2
|
|
108
95
|
{ itemSchema: schema.items.to_openapi(version) }
|
|
109
96
|
else
|
|
110
97
|
{ schema: schema.to_openapi(version) }
|
data/lib/jsapi/version.rb
CHANGED
data/lib/jsapi.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:
|
|
4
|
+
version: 1.4.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: 2025-11-
|
|
11
|
+
date: 2025-11-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description:
|
|
14
14
|
email: denis@dmgoeller.de
|
|
@@ -50,6 +50,10 @@ files:
|
|
|
50
50
|
- lib/jsapi/json/object.rb
|
|
51
51
|
- lib/jsapi/json/string.rb
|
|
52
52
|
- lib/jsapi/json/value.rb
|
|
53
|
+
- lib/jsapi/media.rb
|
|
54
|
+
- lib/jsapi/media/range.rb
|
|
55
|
+
- lib/jsapi/media/type.rb
|
|
56
|
+
- lib/jsapi/media/type_and_subtype.rb
|
|
53
57
|
- lib/jsapi/meta.rb
|
|
54
58
|
- lib/jsapi/meta/callable.rb
|
|
55
59
|
- lib/jsapi/meta/callable/symbol_evaluator.rb
|