zero-rails_openapi 1.4.0 → 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.
@@ -10,7 +10,7 @@ module AutoGenDoc
10
10
  def inherited(subclass)
11
11
  super
12
12
  subclass.class_eval do
13
- break unless self.name.match? /sController|sDoc/
13
+ break unless self.name.match?(/sController|sDoc/)
14
14
  ctrl_path self.name.sub('Doc', '').downcase.gsub('::', '/') if self.name.match?(/sDoc/)
15
15
  open_api_dry
16
16
  end
@@ -3,6 +3,7 @@ class Api::V1::ExamplesController < Api::V1::BaseController
3
3
 
4
4
  components do
5
5
  schema :DogSchema => [ String, dft: 'doge' ]
6
+ schema :PetSchema => [ not: [ Integer, Boolean ] ]
6
7
  query! :UidQuery => [ :uid, String, desc: 'user uid' ]
7
8
  path! :IdPath => [ :id, Integer, desc: 'product id' ]
8
9
  resp :BadRqResp => [ 'bad request', :json ]
@@ -27,7 +28,20 @@ class Api::V1::ExamplesController < Api::V1::BaseController
27
28
  query :email, String, lth: :ge_3, default: email # is_a: :email
28
29
  file :pdf, 'upload a file: the media type should be application/pdf'
29
30
 
31
+ query :test_type, type: String
32
+ query :combination, one_of: [ :DogSchema, String, { type: Integer, desc: 'integer input'}]
33
+ form '', data: {
34
+ :combination => { any_of: [ Integer, String ] }
35
+ }
36
+
30
37
  response :success, 'success response', :json, type: :DogSchema
38
+ merge_to_resp 200, by: {
39
+ data: {
40
+ type: [
41
+ String
42
+ ]
43
+ }
44
+ }
31
45
 
32
46
  security :ApiKeyAuth
33
47
  end
@@ -1,9 +1,8 @@
1
1
  class V2::GoodsDoc < BaseDoc
2
2
  SCHEMA_DRY = { a: 1, b: 2 }
3
3
 
4
- api :index, 'GET list of goods.', builder: :index, # jbuilder templates is set in initializers/open_api.rb
5
- use: [ 'Token', :page, :rows ] do # use parameters write in AutoGenDoc#api_dry
6
- # skip: [ 'Token' ] do # you can also skip parameters
4
+ # skip: [ 'Token' ] do # you can also skip parameters
5
+ api :index, 'GET list of goods.', use: [ 'Token', :page, :rows ] do # use parameters write in AutoGenDoc#api_dry
7
6
  desc 'listing goods',
8
7
  view!: 'search view, allows:<br/>',
9
8
  search_type!: 'search field, allows:<br/>'
@@ -28,7 +27,7 @@ class V2::GoodsDoc < BaseDoc
28
27
  end
29
28
 
30
29
 
31
- api :create, 'POST create a good', builder: :success_or_not, use: 'Token' do
30
+ api :create, 'POST create a good', use: 'Token' do
32
31
  form! 'for creating a good', data: {
33
32
  :name! => { type: String, desc: 'good\'s name' },
34
33
  :category_id! => { type: Integer, desc: 'sub_category\'s id', npmt: true, range: { ge: 1 }, as: :cate },
@@ -46,8 +45,8 @@ class V2::GoodsDoc < BaseDoc
46
45
  end
47
46
 
48
47
 
49
- api :show, 'GET the specified Good.', builder: :show, use: [ 'Token', :id ]
48
+ api :show, 'GET the specified Good.', use: [ 'Token', :id ]
50
49
 
51
50
 
52
- api :destroy, 'DELETE the specified Good.', builder: :success_or_not, use: [ 'Token', :id ]
51
+ api :destroy, 'DELETE the specified Good.', use: [ 'Token', :id ]
53
52
  end
@@ -80,7 +80,7 @@ OpenApi::Config.tap do |c|
80
80
  # The securitySchemes and security keywords are used to describe the authentication methods used in your API.
81
81
  # https://swagger.io/docs/specification/authentication/
82
82
  # Security Scheme Object: An object to hold reusable Security Scheme Objects.
83
- security_schemes: {
83
+ securitySchemes: {
84
84
  ApiKeyAuth: { type: 'apiKey', name: 'server_token', in: 'query' },
85
85
  Token: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' }
86
86
  },
@@ -94,57 +94,6 @@ OpenApi::Config.tap do |c|
94
94
  }
95
95
  }
96
96
 
97
- c.generate_jbuilder_file = true
98
- c.overwrite_jbuilder_file = false
99
- c.jbuilder_templates = {
100
- index: (
101
- <<~FILE
102
- # *** Generated by ZRO [ please make sure that you have checked this file ] ***
103
- json.partial! 'api/base', total: @data.size
104
-
105
- json.data do
106
- # @data = @data.page(@page).per(@rows) if @page || @rows
107
- # json.array! @data do |datum|
108
- json.array! @data.page(@page).per(@rows) do |datum|
109
- json.(datum, *datum.show_attrs) if datum.present?
110
- end
111
- end
112
- FILE
113
- ),
114
-
115
- show: (
116
- <<~FILE
117
- # *** Generated by ZRO [ please make sure that you have checked this file ] ***
118
- json.partial! 'api/base', total: 1
119
-
120
- json.data do
121
- json.array! [ @data ] do |datum|
122
- json.(datum, *datum.show_attrs) if datum.present?
123
- end
124
- end
125
- FILE
126
- ),
127
-
128
- success: (
129
- <<~FILE
130
- # *** Generated by ZRO [ please make sure that you have checked this file ] ***
131
- json.partial! 'api/success'
132
- FILE
133
- ),
134
-
135
- success_or_not: (
136
- <<~FILE
137
- # *** Generated by ZRO [ please make sure that you have checked this file ] ***
138
- unless @status
139
- # @_code, @_msg = @error_info.present? ? @error_info : ApiError.action_failed.info
140
- end
141
-
142
- json.partial! 'api/base', total: 0
143
- json.data ''
144
- FILE
145
- ),
146
- }
147
-
148
97
  end
149
98
 
150
99
  Object.const_set('Boolean', 'boolean') # Support `Boolean` writing in DSL
@@ -1,6 +1,5 @@
1
1
  module OpenApi
2
2
  module Helpers
3
- # TODO: comment-block doc
4
3
  def truly_present?(obj)
5
4
  obj == false || obj.present?
6
5
  end
@@ -24,11 +24,8 @@ module OpenApi
24
24
  end
25
25
 
26
26
  def desc
27
- if __desc.present?
28
- schema.preprocess_with_desc __desc, self[:name]
29
- else
30
- _desc
31
- end
27
+ return _desc unless __desc.present?
28
+ schema.preprocess_with_desc __desc, self[:name]
32
29
  end
33
30
 
34
31
 
@@ -2,11 +2,13 @@ require 'oas_objs/helpers'
2
2
  require 'open_api/config'
3
3
  require 'oas_objs/ref_obj'
4
4
  require 'oas_objs/example_obj'
5
+ require 'oas_objs/schema_obj_helpers'
5
6
 
6
7
  module OpenApi
7
8
  module DSL
8
9
  # https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#schemaObject
9
10
  class SchemaObj < Hash
11
+ include SchemaObjHelpers
10
12
  include Helpers
11
13
 
12
14
  attr_accessor :processed, :type
@@ -28,19 +30,20 @@ module OpenApi
28
30
  return processed if @preprocessed
29
31
 
30
32
  processed.merge! processed_type
31
- reducx processed_enum_and_length,
32
- processed_range,
33
- processed_is_and_format(param_name),
34
- {
35
- pattern: _pattern&.inspect&.delete('/'),
36
- default: _default.nil? ? nil : '_default',
37
- examples: self[:examples].present? ? ExampleObj.new(self[:examples], self[:exp_by]).process : nil
38
- },
39
- { as: _as, permit: _permit, not_permit: _npermit, req_if: _req_if, opt_if: _opt_if }
40
- then_merge!
33
+ reducx(
34
+ processed_enum_and_length,
35
+ processed_range,
36
+ processed_is_and_format(param_name),
37
+ {
38
+ pattern: _pattern&.inspect&.delete('/'),
39
+ default: _default.nil? ? nil : '_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 }
43
+ ).then_merge!
41
44
  processed[:default] = _default unless _default.nil?
42
45
 
43
- reducx(processed_desc options).then_merge!
46
+ reducx(processed_desc(options)).then_merge!
44
47
  end
45
48
 
46
49
  alias process process_for
@@ -53,44 +56,16 @@ module OpenApi
53
56
  end
54
57
 
55
58
  def processed_desc(options)
56
- result = __desc ? self.__desc = process_desc : _desc
59
+ result = __desc ? self.__desc = auto_generate_desc : _desc
57
60
  options[:desc_inside] ? { description: result } : nil
58
61
  end
59
62
 
60
- # TODO: more info
61
- # TODO: desc configure
62
- def process_desc
63
- if processed[:enum].present?
64
- if @enum_info.present?
65
- @enum_info.each_with_index do |(info, value), index|
66
- __desc.concat "<br/>#{index + 1}/ #{info}: #{value}"
67
- end
68
- else
69
- processed[:enum].each_with_index do |value, index|
70
- __desc.concat "<br/>#{index + 1}/ #{value}"
71
- end
72
- end
73
- end
74
- __desc
75
- end
76
-
77
63
  def processed_type(type = self.type)
78
64
  t = type.class.in?([Hash, Array, Symbol]) ? type : type.to_s.downcase
79
65
  if t.is_a? Hash
80
- # For supporting this:
81
- # form 'desc', data: {
82
- # id!: { type: Integer, enum: 0..5, desc: 'user id' }
83
- # }
84
- if t.key?(:type)
85
- SchemaObj.new(t[:type], t).process_for(@prop_name, desc_inside: true)
86
- # For supporting combined schema in nested schema.
87
- elsif (t.keys & %i[ one_of any_of all_of not ]).present?
88
- CombinedSchema.new(t).process_for(@prop_name, desc_inside: true)
89
- else
90
- recursive_obj_type t
91
- end
66
+ processed_hash_type(t)
92
67
  elsif t.is_a? Array
93
- recursive_array_type t
68
+ recursive_array_type(t)
94
69
  elsif t.is_a? Symbol
95
70
  RefObj.new(:schema, t).process
96
71
  elsif t.in? %w[float double int32 int64] # to README: 这些值应该传 string 进来, symbol 只允许 $ref
@@ -106,53 +81,24 @@ module OpenApi
106
81
  end
107
82
  end
108
83
 
109
- def recursive_obj_type(t) # DSL use { prop_name: prop_type } to represent object structure
110
- return processed_type(t) if !t.is_a?(Hash) || (t.keys & %i[ type one_of any_of all_of not ]).present?
111
-
112
- _schema = {
113
- type: 'object',
114
- properties: { },
115
- required: [ ]
116
- }
117
- t.each do |prop_name, prop_type|
118
- @prop_name = prop_name
119
- _schema[:required] << "#{prop_name}".delete('!') if prop_name['!']
120
- _schema[:properties]["#{prop_name}".delete('!').to_sym] = recursive_obj_type prop_type
121
- end
122
- _schema.keep_if(&value_present)
123
- end
124
-
125
- def recursive_array_type(t)
126
- if t.is_a? Array
127
- {
128
- type: 'array',
129
- # TODO: [[String], [Integer]] <= One Of? Object?(0=>[S], 1=>[I])
130
- items: recursive_array_type(t.first)
131
- }
84
+ def processed_hash_type(t)
85
+ # For supporting this:
86
+ # form 'desc', data: {
87
+ # id!: { type: Integer, enum: 0..5, desc: 'user id' }
88
+ # }
89
+ if t.key?(:type)
90
+ SchemaObj.new(t[:type], t).process_for(@prop_name, desc_inside: true)
91
+ # For supporting combined schema in nested schema.
92
+ elsif (t.keys & %i[ one_of any_of all_of not ]).present?
93
+ CombinedSchema.new(t).process_for(@prop_name, desc_inside: true)
132
94
  else
133
- processed_type t
95
+ recursive_obj_type(t)
134
96
  end
135
97
  end
136
98
 
137
99
  def processed_enum_and_length
138
- # Support this writing for auto generating desc from enum.
139
- # enum: {
140
- # 'all_data': :all,
141
- # 'one_page': :one
142
- # }
143
- if _enum.is_a? Hash
144
- @enum_info = _enum
145
- self._enum = _enum.values
146
- end
147
-
148
- %i[_enum _length].each do |key|
149
- value = self.send(key)
150
- self[key] = value.to_a if value.present? && value.is_a?(Range)
151
- end
152
-
153
- # generate_enums_by_enum_array
154
- values = _enum || _value
155
- self._enum = Array(values) if truly_present?(values)
100
+ process_enum_info
101
+ process_enum_lth_range
156
102
 
157
103
  # generate length range fields by _lth array
158
104
  lth = _length || [ ]
@@ -180,16 +126,17 @@ module OpenApi
180
126
  recognize_is_options_in name
181
127
  { }.tap do |it|
182
128
  # `format` that generated in process_type() may be overwrote here.
183
- it.merge!(format: _format || _is) if processed[:format].blank? || _format.present?
184
- it.merge! is: _is
129
+ it[:format] = _format || _is if processed[:format].blank? || _format.present?
130
+ it[:is] = _is
185
131
  end
186
132
  end
187
133
 
188
134
  def recognize_is_options_in(name)
135
+ return unless _is.nil?
189
136
  # identify whether `is` patterns matched the name, if so, generate `is`.
190
137
  Config.is_options.each do |pattern|
191
- self._is = pattern or break if name.match?(/#{pattern}/)
192
- end if _is.nil?
138
+ (self._is = pattern) or break if name.match?(/#{pattern}/)
139
+ end
193
140
  end
194
141
 
195
142
 
@@ -211,10 +158,12 @@ module OpenApi
211
158
  _opt_if: %i[ opt_if opt_when ], # NOT OAS Spec, it's for zero-params_processor
212
159
  }.each do |key, aliases|
213
160
  define_method key do
161
+ return self[key] unless self[key].nil?
162
+
214
163
  aliases.each do |alias_name|
215
164
  break if self[key] == false
216
165
  self[key] ||= self[alias_name]
217
- end if self[key].nil?
166
+ end
218
167
  self[key]
219
168
  end
220
169
  define_method "#{key}=" do |value| self[key] = value end
@@ -0,0 +1,68 @@
1
+ module OpenApi
2
+ module DSL
3
+ module SchemaObjHelpers
4
+ # TODO: more info and desc configure
5
+ def auto_generate_desc
6
+ if processed[:enum].present?
7
+ if @enum_info.present?
8
+ @enum_info.each_with_index do |(info, value), index|
9
+ __desc.concat "<br/>#{index + 1}/ #{info}: #{value}"
10
+ end
11
+ else
12
+ processed[:enum].each_with_index do |value, index|
13
+ __desc.concat "<br/>#{index + 1}/ #{value}"
14
+ end
15
+ end
16
+ end
17
+ __desc
18
+ end
19
+
20
+ def recursive_obj_type(t) # ZRO use { prop_name: prop_type } to represent object structure
21
+ return processed_type(t) if !t.is_a?(Hash) || (t.keys & %i[ type one_of any_of all_of not ]).present?
22
+
23
+ _schema = {
24
+ type: 'object',
25
+ properties: { },
26
+ required: [ ]
27
+ }
28
+ t.each do |prop_name, prop_type|
29
+ @prop_name = prop_name
30
+ _schema[:required] << "#{prop_name}".delete('!') if prop_name['!']
31
+ _schema[:properties]["#{prop_name}".delete('!').to_sym] = recursive_obj_type prop_type
32
+ end
33
+ _schema.keep_if(&value_present)
34
+ end
35
+
36
+ def recursive_array_type(t)
37
+ return processed_type(t) unless t.is_a? Array
38
+
39
+ {
40
+ type: 'array',
41
+ # TODO: [[String], [Integer]] <= One Of? Object?(0=>[S], 1=>[I])
42
+ items: recursive_array_type(t.first)
43
+ }
44
+ end
45
+
46
+ def process_enum_lth_range
47
+ self[:_enum] = _enum.to_a if _enum.present? && _enum.is_a?(Range)
48
+ self[:_length] = _length.to_a if _length.present? && _length.is_a?(Range)
49
+
50
+ # generate_enums_by_enum_array
51
+ values = _enum || _value
52
+ self._enum = Array(values) if truly_present?(values)
53
+ end
54
+
55
+ def process_enum_info
56
+ # Support this writing for auto generating desc from enum.
57
+ # enum: {
58
+ # 'all_data': :all,
59
+ # 'one_page': :one
60
+ # }
61
+ if _enum.is_a? Hash
62
+ @enum_info = _enum
63
+ self._enum = _enum.values
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -14,10 +14,18 @@ module OpenApi
14
14
  true
15
15
  end
16
16
 
17
+ cattr_accessor :doc_location do
18
+ ['./app/**/*_doc.rb']
19
+ end
20
+
17
21
  cattr_accessor :rails_routes_file do
18
22
  nil
19
23
  end
20
24
 
25
+ cattr_accessor :active_record_base do
26
+ ApplicationRecord
27
+ end
28
+
21
29
  # Everything about OAS3 is on https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md
22
30
  # Getting started: https://swagger.io/docs/specification/basic-structure/
23
31
  cattr_accessor :open_api_docs do
@@ -9,8 +9,8 @@ module OpenApi
9
9
  open_api_docs[name] = { root_controller: root_controller }
10
10
  end
11
11
 
12
- def info version:, title:, **addition
13
- open_api_docs[@api][:info] = { version: version, title: title, **addition }
12
+ def info version:, title:, desc: '', **addition
13
+ open_api_docs[@api][:info] = { version: version, title: title, description: desc, **addition }
14
14
  end
15
15
 
16
16
  def server url, desc: ''
@@ -19,7 +19,7 @@ module OpenApi
19
19
 
20
20
  def security_scheme scheme_name, other_info# = { }
21
21
  other_info[:description] = other_info.delete(:desc) if other_info.key?(:desc)
22
- (open_api_docs[@api][:security_schemes] ||= { })[scheme_name] = other_info
22
+ (open_api_docs[@api][:securitySchemes] ||= { })[scheme_name] = other_info
23
23
  end
24
24
 
25
25
  def base_auth scheme_name, other_info = { }
@@ -42,7 +42,7 @@ module OpenApi
42
42
  class << self
43
43
  alias global_security global_security_require
44
44
  alias global_auth global_security_require
45
- alias auth_scheme security_scheme
45
+ alias auth_scheme security_scheme
46
46
  end
47
47
  end
48
48
  end