Class: Taro::Export::OpenAPIv3
- Inherits:
-
Base
- Object
- Base
- Taro::Export::OpenAPIv3
show all
- Defined in:
- lib/taro/export/open_api_v3.rb
Overview
rubocop:disable Metrics/ClassLength
Instance Attribute Summary collapse
Attributes inherited from Base
#result
Instance Method Summary
collapse
Methods inherited from Base
call, #to_json, #to_yaml, #write_to_file
Constructor Details
Returns a new instance of OpenAPIv3.
4
5
6
7
|
# File 'lib/taro/export/open_api_v3.rb', line 4
def initialize
super
@schemas = {}
end
|
Instance Attribute Details
#schemas ⇒ Object
Returns the value of attribute schemas.
2
3
4
|
# File 'lib/taro/export/open_api_v3.rb', line 2
def schemas
@schemas
end
|
Instance Method Details
#assert_unique_openapi_name(type) ⇒ Object
241
242
243
244
245
246
247
248
249
250
|
# File 'lib/taro/export/open_api_v3.rb', line 241
def assert_unique_openapi_name(type)
@name_to_type_map ||= {}
if (prev = @name_to_type_map[type.openapi_name]) && !prev.equivalent?(type)
raise Taro::InvariantError, <<~MSG
Duplicate openapi_name "#{type.openapi_name}" for types #{prev} and #{type}
MSG
else
@name_to_type_map[type.openapi_name] = type
end
end
|
#call(declarations:, title:, version:) ⇒ Object
9
10
11
12
13
14
15
|
# File 'lib/taro/export/open_api_v3.rb', line 9
def call(declarations:, title:, version:)
@result = { openapi: '3.1.0', info: { title:, version: } }
paths = export_paths(declarations)
@result[:paths] = paths.sort.to_h if paths.any?
@result[:components] = { schemas: schemas.sort.to_h } if schemas.any?
self
end
|
#custom_scalar_type?(type) ⇒ Boolean
139
140
141
|
# File 'lib/taro/export/open_api_v3.rb', line 139
def custom_scalar_type?(type)
type < Taro::Types::ScalarType && (type.openapi_pattern || type.deprecated)
end
|
#custom_scalar_type_details(scalar) ⇒ Object
232
233
234
235
236
237
238
239
|
# File 'lib/taro/export/open_api_v3.rb', line 232
def custom_scalar_type_details(scalar)
{
type: scalar.openapi_type,
deprecated: scalar.deprecated,
description: scalar.desc,
pattern: scalar.openapi_pattern,
}.compact
end
|
#enum_type_details(enum) ⇒ Object
214
215
216
217
218
219
220
221
|
# File 'lib/taro/export/open_api_v3.rb', line 214
def enum_type_details(enum)
{
type: enum.item_type.openapi_type,
deprecated: enum.deprecated,
description: enum.desc,
enum: enum.values,
}.compact
end
|
#export_complex_field_ref(field) ⇒ Object
160
161
162
163
164
165
166
167
168
169
170
171
|
# File 'lib/taro/export/open_api_v3.rb', line 160
def export_complex_field_ref(field)
ref = (field.type)
return ref if field_metadata(field).empty? && !field.null
if field.null
{ oneOf: [ref, { type: 'null' }] }
else { allOf: [ref] }
end.merge(field_metadata(field))
end
|
#export_field(field) ⇒ Object
143
144
145
146
147
148
149
|
# File 'lib/taro/export/open_api_v3.rb', line 143
def export_field(field)
if field.type < Taro::Types::ScalarType
export_scalar_field(field)
else
export_complex_field_ref(field)
end
end
|
#export_parameter(field) ⇒ Object
67
68
69
70
71
72
73
74
75
76
77
|
# File 'lib/taro/export/open_api_v3.rb', line 67
def export_parameter(field)
validate_path_or_query_parameter(field)
{
name: field.name,
deprecated: field.deprecated,
description: field.desc,
required: field.required,
schema: export_field(field).except(:deprecated, :description),
}.compact
end
|
#export_paths(declarations) ⇒ Object
17
18
19
20
21
22
23
24
|
# File 'lib/taro/export/open_api_v3.rb', line 17
def export_paths(declarations)
declarations.sort.each_with_object({}) do |declaration, paths|
declaration.routes.each do |route|
paths[route.openapi_path] ||= {}
paths[route.openapi_path].merge! export_route(route, declaration)
end
end
end
|
#export_route(route, declaration) ⇒ Object
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
# File 'lib/taro/export/open_api_v3.rb', line 26
def export_route(route, declaration)
{
route.verb.to_sym => {
deprecated: declaration.deprecated,
description: declaration.desc,
summary: declaration.summary,
tags: declaration.tags,
operationId: route.openapi_operation_id,
parameters: route_parameters(declaration, route),
requestBody: request_body(declaration, route),
responses: responses(declaration),
}.compact,
}
end
|
#export_scalar_field(field) ⇒ Object
151
152
153
154
155
156
157
158
|
# File 'lib/taro/export/open_api_v3.rb', line 151
def export_scalar_field(field)
base = { type: field.openapi_type, format: field.openapi_format }.compact
base = { oneOf: [base, { type: 'null' }] } if field.null
base.merge(field_metadata(field))
end
|
#export_type(type) ⇒ Object
131
132
133
134
135
136
137
|
# File 'lib/taro/export/open_api_v3.rb', line 131
def export_type(type)
if type < Taro::Types::ScalarType && !custom_scalar_type?(type)
{ type: type.openapi_type, format: type.openapi_format }.compact
else
(type)
end
end
|
182
183
184
185
186
|
# File 'lib/taro/export/open_api_v3.rb', line 182
def (type)
assert_unique_openapi_name(type)
schemas[type.openapi_name.to_sym] ||= type_details(type)
{ '$ref': "#/components/schemas/#{type.openapi_name}" }
end
|
173
174
175
176
177
178
179
180
|
# File 'lib/taro/export/open_api_v3.rb', line 173
def field_metadata(field)
meta = {}
meta[:description] = field.desc if field.desc
meta[:deprecated] = field.deprecated unless field.deprecated.nil?
meta[:default] = field.default if field.default_specified?
meta[:enum] = field.enum if field.enum
meta
end
|
#list_type_details(list) ⇒ Object
223
224
225
226
227
228
229
230
|
# File 'lib/taro/export/open_api_v3.rb', line 223
def list_type_details(list)
{
type: 'array',
deprecated: list.deprecated,
description: list.desc,
items: export_type(list.item_type),
}.compact
end
|
#object_type_details(type) ⇒ Object
202
203
204
205
206
207
208
209
210
211
212
|
# File 'lib/taro/export/open_api_v3.rb', line 202
def object_type_details(type)
required = type.fields.values.select(&:required).map(&:name)
{
type: type.openapi_type,
deprecated: type.deprecated,
description: type.desc,
required: (required if required.any?),
properties: type.fields.to_h { |name, f| [name, export_field(f)] },
additionalProperties: (true if type.additional_properties?),
}.compact
end
|
#path_parameters(declaration, route) ⇒ Object
45
46
47
48
49
50
51
52
53
54
55
|
# File 'lib/taro/export/open_api_v3.rb', line 45
def path_parameters(declaration, route)
route.path_params.map do |param_name|
param_field = declaration.params.fields[param_name] || raise(
Taro::InvariantError,
"Declaration missing for path param #{param_name} of route #{route}"
)
export_parameter(param_field).merge(in: 'path', required: true)
end
end
|
#query_parameters(declaration, route) ⇒ Object
57
58
59
60
61
62
63
64
65
|
# File 'lib/taro/export/open_api_v3.rb', line 57
def query_parameters(declaration, route)
return [] if route.can_have_request_body?
declaration.params.fields.filter_map do |name, param_field|
next if route.path_params.include?(name)
export_parameter(param_field).merge(in: 'query')
end
end
|
#request_body(declaration, route) ⇒ Object
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
# File 'lib/taro/export/open_api_v3.rb', line 87
def request_body(declaration, route)
return unless route.can_have_request_body?
params = declaration.params
body_param_fields = params.fields.reject do |name, _field|
route.path_params.include?(name)
end
return unless body_param_fields.any?
body_input_type = Class.new(params)
body_input_type.fields.replace(body_param_fields)
body_input_type.openapi_name = "#{route.openapi_operation_id}_Input"
use_refs = !declaration.polymorphic_route?
schema = request_body_schema(body_input_type, use_refs:)
{ content: { 'application/json': { schema: } } }
end
|
#request_body_schema(type, use_refs:) ⇒ Object
108
109
110
111
112
113
114
|
# File 'lib/taro/export/open_api_v3.rb', line 108
def request_body_schema(type, use_refs:)
if use_refs
(type)
else
type_details(type)
end
end
|
#responses(declaration) ⇒ Object
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
# File 'lib/taro/export/open_api_v3.rb', line 116
def responses(declaration)
declaration.returns.sort.to_h do |code, type|
description = declaration.return_descriptions[code] || type.desc ||
Taro::StatusCode.coerce_to_message(code)
[
code.to_s,
{
description:,
content: { 'application/json': { schema: export_type(type) } },
}
]
end
end
|
#route_parameters(declaration, route) ⇒ Object
41
42
43
|
# File 'lib/taro/export/open_api_v3.rb', line 41
def route_parameters(declaration, route)
path_parameters(declaration, route) + query_parameters(declaration, route)
end
|
#type_details(type) ⇒ Object
188
189
190
191
192
193
194
195
196
197
198
199
200
|
# File 'lib/taro/export/open_api_v3.rb', line 188
def type_details(type)
if type.respond_to?(:fields) object_type_details(type)
elsif type < Taro::Types::EnumType
enum_type_details(type)
elsif type < Taro::Types::ListType
list_type_details(type)
elsif custom_scalar_type?(type)
custom_scalar_type_details(type)
else
raise Taro::InvariantError, "Unexpected type: #{type}"
end
end
|
#validate_path_or_query_parameter(field) ⇒ Object
79
80
81
82
83
84
85
|
# File 'lib/taro/export/open_api_v3.rb', line 79
def validate_path_or_query_parameter(field)
ok = %i[string integer]
ok.include?(field.type.openapi_type) || raise(Taro::ArgumentError, <<~MSG)
Unsupported #{field.openapi_type} as path/query param "#{field.name}",
expected one of: #{ok.join(', ')}
MSG
end
|