zero-rails_openapi 1.5.2 → 1.5.3
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 +16 -0
- data/Gemfile.lock +5 -3
- data/README.md +149 -149
- data/README_zh.md +183 -167
- data/documentation/examples/examples_controller.rb +1 -1
- data/documentation/parameter.md +3 -3
- data/lib/oas_objs/param_obj.rb +7 -18
- data/lib/oas_objs/ref_obj.rb +2 -1
- data/lib/oas_objs/schema_obj.rb +26 -62
- data/lib/oas_objs/schema_obj_helpers.rb +37 -21
- data/lib/open_api/dsl/api_info.rb +24 -41
- data/lib/open_api/dsl/common_dsl.rb +3 -2
- data/lib/open_api/dsl/components.rb +25 -33
- data/lib/open_api/dsl/helpers.rb +24 -8
- data/lib/open_api/dsl.rb +3 -2
- data/lib/open_api/generator.rb +7 -7
- data/lib/open_api/version.rb +1 -1
- data/zero-rails_openapi.gemspec +3 -0
- metadata +16 -2
@@ -54,7 +54,7 @@ class Api::V1::ExamplesController < Api::V1::BaseController
|
|
54
54
|
:name! => String, # <= schema_type is `String`
|
55
55
|
:password! => { type: String, pattern: /[0-9]{6,10}/, desc: 'password' },
|
56
56
|
# optional
|
57
|
-
:remarks => { type: String, desc: 'remarks' }, # <= schema_type is `String`, and
|
57
|
+
:remarks => { type: String, desc: 'remarks' }, # <= schema_type is `String`, and schema_info is { desc: '..' }
|
58
58
|
}
|
59
59
|
end
|
60
60
|
end
|
data/documentation/parameter.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
### More Explanation for `param` and `
|
1
|
+
### More Explanation for `param` and `schema_info`
|
2
2
|
|
3
3
|
#### param_type (param_location)
|
4
4
|
OpenAPI 3.0 distinguishes between the following parameter types based on the parameter location:
|
@@ -15,7 +15,7 @@ Parameter's (schema) type. We call it `schema_type` because it is inside SchemaO
|
|
15
15
|
|
16
16
|
Support all [data types](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#dataTypes) defined in OAS.
|
17
17
|
|
18
|
-
In addition, you can use `format` in
|
18
|
+
In addition, you can use `format` in schema_info to define in fine detail the data type being used, like:
|
19
19
|
int32, float, date ...
|
20
20
|
All the types you can use as following:
|
21
21
|
- **String, 'binary', 'base64'**
|
@@ -41,7 +41,7 @@ All the types you can use as following:
|
|
41
41
|
#### Schema Hash
|
42
42
|
|
43
43
|
The [[schema]](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#schemaObject) defining the type used for the parameter.
|
44
|
-
|
44
|
+
schema_info(optional) will be used to generate Schema Object inside Parameter Object.
|
45
45
|
[source code](https://github.com/zhandao/zero-rails_openapi/blob/master/lib/oas_objs/schema_obj.rb)
|
46
46
|
You can set the schema by following keys (all are optional), the words in parentheses are available aliases of the keys:
|
47
47
|
- **enum (values, allowable_values)**
|
data/lib/oas_objs/param_obj.rb
CHANGED
@@ -19,29 +19,18 @@ module OpenApi
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def process
|
22
|
-
assign(desc).to_processed
|
23
|
-
|
22
|
+
assign(desc).to_processed :description
|
23
|
+
assign(schema.process).to_processed :schema
|
24
|
+
processed
|
24
25
|
end
|
25
26
|
|
26
27
|
def desc
|
27
|
-
return
|
28
|
-
schema.
|
28
|
+
return self[:desc] || self[:description] if (self[:desc!] || self[:description!]).blank?
|
29
|
+
schema.__desc # not a copy of __desc, means desc() will change if schema.__desc changes.
|
29
30
|
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
# This mapping allows user to select the aliases in DSL writing,
|
34
|
-
# without increasing the complexity of the implementation.
|
35
|
-
{ # SELF_MAPPING
|
36
|
-
_range: %i[ range number_range ],
|
37
|
-
_length: %i[ length lth ],
|
38
|
-
_desc: %i[ desc description ],
|
39
|
-
__desc: %i[ desc! description! ],
|
40
|
-
}.each do |key, aliases|
|
41
|
-
define_method key do
|
42
|
-
aliases.each { |alias_name| self[key] ||= self[alias_name] } if self[key].nil?
|
43
|
-
self[key]
|
44
|
-
end
|
32
|
+
def name
|
33
|
+
processed[:name]
|
45
34
|
end
|
46
35
|
end
|
47
36
|
end
|
data/lib/oas_objs/ref_obj.rb
CHANGED
data/lib/oas_objs/schema_obj.rb
CHANGED
@@ -13,55 +13,30 @@ module OpenApi
|
|
13
13
|
|
14
14
|
attr_accessor :processed, :type, :preprocessed
|
15
15
|
|
16
|
-
def initialize(type,
|
16
|
+
def initialize(type, schema_info)
|
17
17
|
self.preprocessed = false
|
18
18
|
self.processed = { }
|
19
|
-
# [Note] Here is no limit to type, even if the input isn't up to OAS,
|
20
|
-
# like: double, float, hash.
|
21
|
-
# My consideration is, OAS can't express some cases like:
|
22
|
-
# `total_price` should be double, is_a `price`, and match /^.*\..*$/
|
23
|
-
# However, user can decide how to write --
|
24
|
-
# `type: number, format: double`, or `type: double`
|
25
19
|
self.type = type
|
26
|
-
merge!
|
20
|
+
merge! schema_info
|
27
21
|
end
|
28
22
|
|
29
23
|
def process(options = { inside_desc: false })
|
30
|
-
return processed if preprocessed
|
31
|
-
|
32
24
|
processed.merge!(processed_type)
|
33
|
-
reducx(
|
34
|
-
processed_enum_and_length,
|
35
|
-
processed_range,
|
36
|
-
processed_is_and_format,
|
37
|
-
{
|
38
|
-
pattern: _pattern.is_a?(String)? _pattern : _pattern&.inspect&.delete('/'),
|
39
|
-
default: _default,
|
40
|
-
examples: self[:examples].present? ? ExampleObj.new(self[:examples], self[:exp_by]).process : nil
|
41
|
-
},
|
42
|
-
{ as: _as, permit: _permit, not_permit: _npermit, req_if: _req_if, opt_if: _opt_if, blankable: _blank },
|
43
|
-
).then_merge!
|
44
|
-
reducx(processed_desc(options)).then_merge! # TODO
|
45
|
-
end
|
46
|
-
|
47
|
-
def preprocess_with_desc desc
|
48
|
-
self.__desc = desc
|
49
|
-
process
|
50
|
-
self.preprocessed = true
|
51
|
-
__desc
|
25
|
+
reducx(enum_and_length, range, is_and_format, pattern_default_and_other, desc(options)).then_merge!
|
52
26
|
end
|
53
27
|
|
54
|
-
def
|
28
|
+
def desc(inside_desc:)
|
55
29
|
result = __desc ? auto_generate_desc : _desc
|
56
|
-
|
30
|
+
return unless inside_desc
|
31
|
+
{ description: result }
|
57
32
|
end
|
58
33
|
|
59
34
|
def processed_type(type = self.type)
|
60
35
|
t = type.class.in?([Hash, Array, Symbol]) ? type : type.to_s.downcase
|
61
36
|
if t.is_a? Hash
|
62
|
-
|
37
|
+
hash_type(t)
|
63
38
|
elsif t.is_a? Array
|
64
|
-
|
39
|
+
array_type(t)
|
65
40
|
elsif t.is_a? Symbol
|
66
41
|
RefObj.new(:schema, t).process
|
67
42
|
elsif t.in? %w[ float double int32 int64 ]
|
@@ -77,33 +52,17 @@ module OpenApi
|
|
77
52
|
end
|
78
53
|
end
|
79
54
|
|
80
|
-
def
|
81
|
-
# For supporting this:
|
82
|
-
# form 'desc', type: {
|
83
|
-
# id!: { type: Integer, enum: 0..5, desc: 'user id' }
|
84
|
-
# }, should have description within schema
|
85
|
-
if t.key?(:type)
|
86
|
-
SchemaObj.new(t[:type], t).process(inside_desc: true)
|
87
|
-
|
88
|
-
# For supporting combined schema in nested schema.
|
89
|
-
elsif (t.keys & %i[ one_of any_of all_of not ]).present?
|
90
|
-
CombinedSchema.new(t).process(inside_desc: true)
|
91
|
-
else
|
92
|
-
processed_obj_type(t)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def processed_enum_and_length
|
55
|
+
def enum_and_length
|
97
56
|
process_enum_info
|
98
57
|
process_range_enum_and_lth
|
99
58
|
|
100
59
|
# generate length range fields by _lth array
|
101
|
-
if (lth = _length ||
|
60
|
+
if (lth = _length || '').is_a?(Array)
|
102
61
|
min, max = [lth.first&.to_i, lth.last&.to_i]
|
103
62
|
elsif lth['ge']
|
104
|
-
max = lth.to_s.split('_').last.to_i
|
105
|
-
elsif lth['le']
|
106
63
|
min = lth.to_s.split('_').last.to_i
|
64
|
+
elsif lth['le']
|
65
|
+
max = lth.to_s.split('_').last.to_i
|
107
66
|
end
|
108
67
|
|
109
68
|
if processed[:type] == 'array'
|
@@ -113,23 +72,32 @@ module OpenApi
|
|
113
72
|
end.merge!(enum: _enum).keep_if &value_present
|
114
73
|
end
|
115
74
|
|
116
|
-
def
|
75
|
+
def range
|
117
76
|
range = _range || { }
|
118
77
|
{
|
119
|
-
|
78
|
+
minimum: range[:gt] || range[:ge],
|
120
79
|
exclusiveMinimum: range[:gt].present? ? true : nil,
|
121
|
-
|
80
|
+
maximum: range[:lt] || range[:le],
|
122
81
|
exclusiveMaximum: range[:lt].present? ? true : nil
|
123
82
|
}.keep_if &value_present
|
124
83
|
end
|
125
84
|
|
126
|
-
def
|
85
|
+
def is_and_format
|
127
86
|
result = { is: _is }
|
128
87
|
# `format` that generated in process_type() may be overwrote here.
|
129
88
|
result[:format] = _format || _is if processed[:format].blank? || _format.present?
|
130
89
|
result
|
131
90
|
end
|
132
91
|
|
92
|
+
def pattern_default_and_other
|
93
|
+
{
|
94
|
+
pattern: _pattern.is_a?(String)? _pattern : _pattern&.inspect&.delete('/'),
|
95
|
+
default: _default,
|
96
|
+
examples: self[:examples].present? ? ExampleObj.new(self[:examples], self[:exp_by]).process : nil,
|
97
|
+
as: _as, permit: _permit, not_permit: _npermit, req_if: _req_if, opt_if: _opt_if, blankable: _blank
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
133
101
|
|
134
102
|
{ # SELF_MAPPING
|
135
103
|
_enum: %i[ enum in values allowable_values ],
|
@@ -151,11 +119,7 @@ module OpenApi
|
|
151
119
|
}.each do |key, aliases|
|
152
120
|
define_method key do
|
153
121
|
return self[key] unless self[key].nil?
|
154
|
-
|
155
|
-
aliases.each do |alias_name|
|
156
|
-
break if self[key] == false
|
157
|
-
self[key] ||= self[alias_name]
|
158
|
-
end
|
122
|
+
aliases.each { |alias_name| self[key] = self[alias_name] if self[key].nil? }
|
159
123
|
self[key]
|
160
124
|
end
|
161
125
|
define_method "#{key}=" do |value| self[key] = value end
|
@@ -1,23 +1,23 @@
|
|
1
1
|
module OpenApi
|
2
2
|
module DSL
|
3
3
|
module SchemaObjHelpers
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
def hash_type(t)
|
5
|
+
# For supporting this:
|
6
|
+
# form 'desc', type: {
|
7
|
+
# id!: { type: Integer, enum: 0..5, desc: 'user id' }
|
8
|
+
# }, should have description within schema
|
9
|
+
if t.key?(:type)
|
10
|
+
SchemaObj.new(t[:type], t).process(inside_desc: true)
|
7
11
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
+
# For supporting combined schema in nested schema.
|
13
|
+
elsif (t.keys & %i[ one_of any_of all_of not ]).present?
|
14
|
+
CombinedSchema.new(t).process(inside_desc: true)
|
12
15
|
else
|
13
|
-
|
14
|
-
__desc.concat "<br/>#{index + 1}/ #{value}"
|
15
|
-
end
|
16
|
+
obj_type(t)
|
16
17
|
end
|
17
|
-
__desc
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
20
|
+
def obj_type(t)
|
21
21
|
obj_type = { type: 'object', properties: { }, required: [ ] }
|
22
22
|
|
23
23
|
t.each do |prop_name, prop_type|
|
@@ -27,7 +27,7 @@ module OpenApi
|
|
27
27
|
obj_type.keep_if &value_present
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
30
|
+
def array_type(t)
|
31
31
|
t = t.size == 1 ? t.first : { one_of: t }
|
32
32
|
{
|
33
33
|
type: 'array',
|
@@ -36,16 +36,16 @@ module OpenApi
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def process_range_enum_and_lth
|
39
|
-
self[:_enum] =
|
40
|
-
self[:_length] =
|
39
|
+
self[:_enum] = str_range_toa(_enum) if _enum.is_a?(Range)
|
40
|
+
self[:_length] = str_range_toa(_length) if _length.is_a?(Range)
|
41
41
|
|
42
42
|
values = _enum || _value
|
43
43
|
self._enum = Array(values) if truly_present?(values)
|
44
44
|
end
|
45
45
|
|
46
|
-
def
|
46
|
+
def str_range_toa(val)
|
47
47
|
val_class = val.first.class
|
48
|
-
action = "to_#{val_class.to_s.downcase[0]}"
|
48
|
+
action = :"to_#{val_class.to_s.downcase[0]}"
|
49
49
|
(val.first.to_s..val.last.to_s).to_a.map(&action)
|
50
50
|
end
|
51
51
|
|
@@ -55,10 +55,26 @@ module OpenApi
|
|
55
55
|
# 'all_desc': :all,
|
56
56
|
# 'one_desc': :one
|
57
57
|
# }
|
58
|
-
self._enum ||= self[:enum!]
|
59
|
-
return unless
|
60
|
-
@enum_info =
|
61
|
-
self._enum =
|
58
|
+
self._enum ||= e = self[:enum!]
|
59
|
+
return unless e.is_a? Hash
|
60
|
+
@enum_info = e
|
61
|
+
self._enum = e.values
|
62
|
+
end
|
63
|
+
|
64
|
+
# TODO: more info and desc configure
|
65
|
+
def auto_generate_desc
|
66
|
+
return __desc if _enum.blank?
|
67
|
+
|
68
|
+
if @enum_info.present?
|
69
|
+
@enum_info.each_with_index do |(info, value), index|
|
70
|
+
__desc.concat "<br/>#{index + 1}/ #{info}: #{value}"
|
71
|
+
end
|
72
|
+
else
|
73
|
+
_enum.each_with_index do |value, index|
|
74
|
+
__desc.concat "<br/>#{index + 1}/ #{value}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
__desc
|
62
78
|
end
|
63
79
|
end
|
64
80
|
end
|
@@ -28,27 +28,22 @@ module OpenApi
|
|
28
28
|
self[:description] = desc
|
29
29
|
end
|
30
30
|
|
31
|
-
def param param_type, name, type, required,
|
31
|
+
def param param_type, name, type, required, schema_info = { }
|
32
32
|
return if param_skip.include?(name)
|
33
33
|
return if param_use.present? && param_use.exclude?(name)
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
param_obj = ParamObj.new(name, param_type, type, required, schema_hash)
|
35
|
+
schema_info[:desc] ||= param_descs[name]
|
36
|
+
schema_info[:desc!] ||= param_descs[:"#{name}!"]
|
37
|
+
param_obj = ParamObj.new(name, param_type, type, required, schema_info)
|
40
38
|
# The definition of the same name parameter will be overwritten
|
41
39
|
fill_in_parameters(param_obj)
|
42
40
|
end
|
43
41
|
|
44
42
|
# [ header header! path path! query query! cookie cookie! ]
|
45
|
-
def _param_agent name, type = nil,
|
46
|
-
|
47
|
-
type
|
48
|
-
|
49
|
-
|
50
|
-
schema_hash = CombinedSchema.new(one_of: one_of, all_of: all_of, any_of: any_of, _not: _not) if combined_schema
|
51
|
-
param @param_type.to_s.delete('!'), name, type, (@param_type['!'] ? :req : :opt), schema_hash
|
43
|
+
def _param_agent name, type = nil, **schema_info
|
44
|
+
schema = process_schema_info(type, schema_info)
|
45
|
+
return puts ' ZRO'.red + " Syntax Error: param `#{name}` has no schema type!" if schema[:illegal?]
|
46
|
+
param @param_type, name, schema[:type], @necessity, schema[:combined] || schema[:info]
|
52
47
|
end
|
53
48
|
|
54
49
|
# For supporting this: (just like `form '', data: { }` usage)
|
@@ -58,17 +53,17 @@ module OpenApi
|
|
58
53
|
# }
|
59
54
|
%i[ header header! path path! query query! cookie cookie! ].each do |param_type|
|
60
55
|
define_method "do_#{param_type}" do |by:, **common_schema|
|
61
|
-
by.each do |
|
62
|
-
action = param_type.
|
56
|
+
by.each do |param_name, schema|
|
57
|
+
action = "#{param_type}#{param_name['!']}".sub('!!', '!')
|
63
58
|
type, schema = schema.is_a?(Hash) ? [schema[:type], schema] : [schema, { }]
|
64
|
-
args = [
|
65
|
-
|
59
|
+
args = [ param_name.to_s.delete('!').to_sym, type, schema.reverse_merge!(common_schema) ]
|
60
|
+
send(action, *args)
|
66
61
|
end
|
67
62
|
end
|
68
63
|
end
|
69
64
|
|
70
65
|
def param_ref component_key, *keys
|
71
|
-
self[:parameters]
|
66
|
+
self[:parameters] += [component_key, *keys].map { |key| RefObj.new(:parameter, key) }
|
72
67
|
end
|
73
68
|
|
74
69
|
# options: `exp_by` and `examples`
|
@@ -80,7 +75,7 @@ module OpenApi
|
|
80
75
|
|
81
76
|
# [ body body! ]
|
82
77
|
def _request_body_agent media_type, data: { }, **options
|
83
|
-
request_body
|
78
|
+
request_body @necessity, media_type, data: data, **options
|
84
79
|
end
|
85
80
|
|
86
81
|
def body_ref component_key
|
@@ -95,9 +90,9 @@ module OpenApi
|
|
95
90
|
body! :form, data: data, **options
|
96
91
|
end
|
97
92
|
|
98
|
-
def data name, type = nil,
|
99
|
-
|
100
|
-
form data: { name =>
|
93
|
+
def data name, type = nil, schema_info = { }
|
94
|
+
schema_info[:type] = type if type.present?
|
95
|
+
form data: { name => schema_info }
|
101
96
|
end
|
102
97
|
|
103
98
|
def file media_type, data: { type: File }, **options
|
@@ -109,9 +104,7 @@ module OpenApi
|
|
109
104
|
end
|
110
105
|
|
111
106
|
def response_ref code_compkey_hash
|
112
|
-
code_compkey_hash.each
|
113
|
-
self[:responses][code] = RefObj.new(:response, component_key).process
|
114
|
-
end
|
107
|
+
code_compkey_hash.each { |code, component_key| self[:responses][code] = RefObj.new(:response, component_key) }
|
115
108
|
end
|
116
109
|
|
117
110
|
def security_require scheme_name, scopes: [ ]
|
@@ -128,34 +121,24 @@ module OpenApi
|
|
128
121
|
|
129
122
|
def order *param_names
|
130
123
|
self.param_order = param_names
|
131
|
-
#
|
124
|
+
# be used when `api_dry`
|
132
125
|
self.param_use = param_order if param_use.blank?
|
133
126
|
self.param_skip = param_use - param_order
|
134
127
|
end
|
135
128
|
|
136
129
|
def param_examples exp_by = :all, examples_hash
|
137
|
-
|
138
|
-
exp_by = self[:parameters].map { |p| p[:name] } if exp_by == :all
|
130
|
+
exp_by = self[:parameters].map(&:name) if exp_by == :all
|
139
131
|
self[:examples] = ExampleObj.new(examples_hash, exp_by).process
|
140
132
|
end
|
141
133
|
|
142
134
|
alias examples param_examples
|
143
135
|
|
144
136
|
def process_objs
|
145
|
-
self[:parameters]
|
146
|
-
|
147
|
-
end
|
137
|
+
self[:parameters].map!(&:process)
|
138
|
+
self[:parameters].sort_by! { |param| param_order.index(param[:name]) || Float::INFINITY } if param_order.present?
|
148
139
|
|
149
|
-
|
150
|
-
self[:
|
151
|
-
self[:parameters][param_order.index(p[:name]) || -1] = p
|
152
|
-
end if param_order.present?
|
153
|
-
|
154
|
-
self[:requestBody] = self[:requestBody].try :process
|
155
|
-
|
156
|
-
self[:responses]&.each do |code, obj|
|
157
|
-
self[:responses][code] = obj.process if obj.is_a?(ResponseObj)
|
158
|
-
end
|
140
|
+
self[:requestBody] = self[:requestBody].try(:process)
|
141
|
+
self[:responses].each { |code, response| self[:responses][code] = response.process }
|
159
142
|
end
|
160
143
|
end
|
161
144
|
end
|
@@ -12,14 +12,15 @@ module OpenApi
|
|
12
12
|
module CommonDSL
|
13
13
|
%i[ header header! path path! query query! cookie cookie! ].each do |param_type|
|
14
14
|
define_method param_type do |*args|
|
15
|
-
@
|
15
|
+
@necessity = param_type['!'] ? :req : :opt
|
16
|
+
@param_type = param_type.to_s.delete('!') # OR: caller[0][/`.*'/][1..-2].to_sym
|
16
17
|
_param_agent *args
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
20
21
|
%i[ body body! ].each do |method|
|
21
22
|
define_method method do |*args|
|
22
|
-
@
|
23
|
+
@necessity = method['!'] ? :req : :opt
|
23
24
|
_request_body_agent *args
|
24
25
|
end
|
25
26
|
end
|
@@ -6,51 +6,44 @@ module OpenApi
|
|
6
6
|
include DSL::CommonDSL
|
7
7
|
include DSL::Helpers
|
8
8
|
|
9
|
-
def schema component_key, type = nil,
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
pp "[ZRO] Syntax Error: component schema `#{component_key}` has no type!" and return if schema_hash[:type].nil? && combined_schema.nil?
|
14
|
-
|
15
|
-
combined_schema = CombinedSchema.new(one_of: one_of, all_of: all_of, any_of: any_of, _not: _not) if combined_schema
|
16
|
-
(self[:schemas] ||= { })[component_key.to_s.to_sym] = combined_schema&.process || SchemaObj.new(schema_hash, { }).process
|
9
|
+
def schema component_key, type = nil, **schema_info
|
10
|
+
schema = process_schema_info(type, schema_info, model: component_key)
|
11
|
+
return puts ' ZRO'.red + " Syntax Error: component schema `#{component_key}` has no type!" if schema[:illegal?]
|
12
|
+
self[:schemas][component_key.to_s.to_sym] = (schema[:combined] || SchemaObj.new(type = schema[:info], { })).process
|
17
13
|
end
|
14
|
+
|
18
15
|
arrow_enable :schema
|
19
16
|
|
20
17
|
def example component_key, examples_hash
|
21
|
-
|
18
|
+
self[:examples][component_key] = ExampleObj.new(examples_hash).process
|
22
19
|
end
|
20
|
+
|
23
21
|
arrow_enable :example
|
24
22
|
|
25
|
-
def param component_key, param_type, name, type, required,
|
26
|
-
|
23
|
+
def param component_key, param_type, name, type, required, schema_info = { }
|
24
|
+
self[:parameters][component_key] = ParamObj.new(name, param_type, type, required, schema_info).process
|
27
25
|
end
|
28
26
|
|
29
27
|
# [ header header! path path! query query! cookie cookie! ]
|
30
|
-
def _param_agent component_key, name, type = nil,
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
combined_schema = one_of || all_of || any_of || (_not = binding.local_variable_get(:not))
|
36
|
-
schema_hash = CombinedSchema.new(one_of: one_of, all_of: all_of, any_of: any_of, _not: _not) if combined_schema
|
37
|
-
param component_key,
|
38
|
-
"#{@param_type}".delete('!'), name, type, (@param_type['!'] ? :req : :opt), schema_hash
|
28
|
+
def _param_agent component_key, name, type = nil, **schema_info
|
29
|
+
schema = process_schema_info(type, schema_info)
|
30
|
+
return puts ' ZRO'.red + " Syntax Error: param `#{name}` has no schema type!" if schema[:illegal?]
|
31
|
+
param component_key, @param_type, name, schema[:type], @necessity, schema[:combined] || schema[:info]
|
39
32
|
end
|
33
|
+
|
40
34
|
arrow_enable :_param_agent
|
41
35
|
|
42
|
-
def request_body component_key, required, media_type, data: { }, **options
|
43
|
-
|
44
|
-
cur = (self[:requestBodies] ||= { })[component_key]
|
36
|
+
def request_body component_key, required, media_type, data: { }, desc: '', **options
|
37
|
+
cur = self[:requestBodies][component_key]
|
45
38
|
cur = RequestBodyObj.new(required, desc) unless cur.is_a?(RequestBodyObj)
|
46
39
|
self[:requestBodies][component_key] = cur.add_or_fusion(media_type, { data: data, **options })
|
47
40
|
end
|
48
41
|
|
49
42
|
# [ body body! ]
|
50
43
|
def _request_body_agent component_key, media_type, data: { }, **options
|
51
|
-
request_body component_key,
|
52
|
-
(@method_name['!'] ? :req : :opt), media_type, data: data, **options
|
44
|
+
request_body component_key, @necessity, media_type, data: data, **options
|
53
45
|
end
|
46
|
+
|
54
47
|
arrow_enable :_request_body_agent
|
55
48
|
|
56
49
|
arrow_enable :resp # alias_method 竟然也会指向旧的方法?
|
@@ -58,8 +51,9 @@ module OpenApi
|
|
58
51
|
|
59
52
|
def security_scheme scheme_name, other_info# = { }
|
60
53
|
other_info[:description] = other_info.delete(:desc) if other_info[:desc]
|
61
|
-
|
54
|
+
self[:securitySchemes][scheme_name] = other_info
|
62
55
|
end
|
56
|
+
|
63
57
|
arrow_enable :security_scheme
|
64
58
|
|
65
59
|
alias auth_scheme security_scheme
|
@@ -67,27 +61,25 @@ module OpenApi
|
|
67
61
|
def base_auth scheme_name, other_info = { }
|
68
62
|
security_scheme scheme_name, { type: 'http', scheme: 'basic', **other_info }
|
69
63
|
end
|
64
|
+
|
70
65
|
arrow_enable :base_auth
|
71
66
|
|
72
67
|
def bearer_auth scheme_name, format = 'JWT', other_info = { }
|
73
68
|
security_scheme scheme_name, { type: 'http', scheme: 'bearer', bearerFormat: format, **other_info }
|
74
69
|
end
|
70
|
+
|
75
71
|
arrow_enable :bearer_auth
|
76
72
|
|
77
73
|
def api_key scheme_name, field:, in: 'header', **other_info
|
78
74
|
_in = binding.local_variable_get(:in)
|
79
75
|
security_scheme scheme_name, { type: 'apiKey', name: field, in: _in, **other_info }
|
80
76
|
end
|
77
|
+
|
81
78
|
arrow_enable :api_key
|
82
79
|
|
83
80
|
def process_objs
|
84
|
-
self[:requestBodies]
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
self[:responses]&.each do |code, obj|
|
89
|
-
self[:responses][code] = obj.process if obj.is_a?(ResponseObj)
|
90
|
-
end
|
81
|
+
self[:requestBodies].each { |key, body| self[:requestBodies][key] = body.process }
|
82
|
+
self[:responses].each { |code, response| self[:responses][code] = response.process }
|
91
83
|
end
|
92
84
|
end
|
93
85
|
end
|
data/lib/open_api/dsl/helpers.rb
CHANGED
@@ -6,11 +6,11 @@ module OpenApi
|
|
6
6
|
end
|
7
7
|
|
8
8
|
# :nocov:
|
9
|
-
def load_schema(model)
|
9
|
+
def load_schema(model) # TODO: test
|
10
10
|
# About `show_attrs`, see:
|
11
11
|
# (1) BuilderSupport module: https://github.com/zhandao/zero-rails/blob/master/app/models/concerns/builder_support.rb
|
12
12
|
# (2) config in model: https://github.com/zhandao/zero-rails/tree/master/app/models/good.rb
|
13
|
-
# (3) jbuilder file: https://github.com/zhandao/zero-rails/blob/
|
13
|
+
# (3) jbuilder file: https://github.com/zhandao/zero-rails/blob/master/app/views/api/v1/goods/index.json.jbuilder
|
14
14
|
# In a word, BuilderSupport let you control the `output fields and nested association infos` very easily.
|
15
15
|
if model.respond_to? :show_attrs
|
16
16
|
_load_schema_based_on_show_attr(model)
|
@@ -41,27 +41,43 @@ module OpenApi
|
|
41
41
|
# :nocov:
|
42
42
|
|
43
43
|
def fill_in_parameters(param_obj)
|
44
|
-
|
45
|
-
index = self[:parameters].map { |p| p.processed[:name] if p.is_a?(ParamObj) }.index(name)
|
44
|
+
index = self[:parameters].map(&:name).index(param_obj.name)
|
46
45
|
index.present? ? self[:parameters][index] = param_obj : self[:parameters] << param_obj
|
47
46
|
end
|
48
47
|
|
48
|
+
def _combined_schema(one_of: nil, all_of: nil, any_of: nil, not: nil, **other)
|
49
|
+
input = (_not = binding.local_variable_get(:not)) || one_of || all_of || any_of
|
50
|
+
CombinedSchema.new(one_of: one_of, all_of: all_of, any_of: any_of, _not: _not) if input
|
51
|
+
end
|
52
|
+
|
53
|
+
def process_schema_info(schema_type, schema_info, model: nil)
|
54
|
+
combined_schema = _combined_schema(schema_info)
|
55
|
+
type = schema_info[:type] ||= schema_type
|
56
|
+
schema_info = load_schema(model) if model.try(:superclass) == (Config.active_record_base || ApplicationRecord)
|
57
|
+
{
|
58
|
+
illegal?: type.nil? && combined_schema.nil?,
|
59
|
+
combined: combined_schema,
|
60
|
+
info: schema_info,
|
61
|
+
type: type
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
49
65
|
# Arrow Writing:
|
50
66
|
# response :RespComponent => [ '200', 'success', :json ]
|
51
67
|
# It is equivalent to:
|
52
68
|
# response :RespComponent, '200', 'success', :json
|
53
69
|
# But I think, in the definition of a component,
|
54
|
-
# the key-value (arrow) writing is
|
70
|
+
# the key-value (arrow) writing is more easier to understand.
|
55
71
|
def arrow_writing_support
|
56
72
|
proc do |args, executor|
|
57
|
-
|
58
|
-
send(executor, *
|
73
|
+
args = (args.size == 1 && args.first.is_a?(Hash)) ? args[0].to_a.flatten : args
|
74
|
+
send(executor, *args)
|
59
75
|
end
|
60
76
|
end
|
61
77
|
|
62
78
|
module ClassMethods
|
63
79
|
def arrow_enable method
|
64
|
-
alias_method "_#{method}"
|
80
|
+
alias_method :"_#{method}", method
|
65
81
|
define_method method do |*args|
|
66
82
|
arrow_writing_support.call(args, "_#{method}")
|
67
83
|
end
|