zero-rails_openapi 1.7.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,52 +0,0 @@
1
- class V2::GoodsDoc < ApiDoc
2
- SCHEMA_DRY = { a: 1, b: 2 }
3
-
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
6
- desc 'listing goods',
7
- view!: 'search view, allows:<br/>',
8
- search_type!: 'search field, allows:<br/>'
9
-
10
- # Single `query`
11
- query :view, String, enum!: {
12
- 'all goods (default)': :all,
13
- 'only online': :online,
14
- 'only offline': :offline,
15
- 'expensive goods': :expensive,
16
- 'cheap goods': :cheap,
17
- }, **SCHEMA_DRY # >>> Here is a little trick! <<<
18
- # Batch `query`
19
- do_query by: {
20
- :search_type => { type: String, enum: %w[ name creator category price ] },
21
- :value => String,
22
- :export => { type: Boolean, desc: 'export as Excel format', examples: {
23
- :right_input => true,
24
- :wrong_input => 'wrong input'
25
- }}
26
- }
27
- end
28
-
29
-
30
- api :create, 'POST create a good', use: 'Token' do
31
- form! data: {
32
- :name! => { type: String, desc: 'good\'s name' },
33
- :category_id! => { type: Integer, desc: 'sub_category\'s id', npmt: true, range: { ge: 1 }, as: :cate },
34
- :price! => { type: Float, desc: 'good\'s price', range: { ge: 0 } },
35
- # -- optional
36
- :is_online => { type: Boolean, desc: 'it\'s online?' },
37
- :remarks => { type: String, desc: 'remarks' },
38
- :pic_path => { type: String, desc: 'picture url', is: :url },
39
- },
40
- exp_by: %i[ name category_id price ],
41
- examples: {
42
- :right_input => [ 'good1', 6, 5.7 ],
43
- :wrong_input => [ 'good2', 0, -1 ]
44
- }
45
- end
46
-
47
-
48
- api :show, 'GET the specified Good.', use: [ 'Token', :id ]
49
-
50
-
51
- api :destroy, 'DELETE the specified Good.', use: [ 'Token', :id ]
52
- end
@@ -1,69 +0,0 @@
1
- ### More Explanation for `param` and `schema_info`
2
-
3
- #### param_type (param_location)
4
- OpenAPI 3.0 distinguishes between the following parameter types based on the parameter location:
5
- **header, path, query, cookie**. [more](https://swagger.io/docs/specification/describing-parameters/)
6
-
7
- #### name (param_name)
8
- The name of parameter. It can be Symbol or String.
9
-
10
- If param_type is :path, it must correspond to the associated path segment form
11
- the routing path, for example: if the API path is `/good/:id`, you have to declare a path parameter with name `id` to it.
12
-
13
- #### type (schema_type)
14
- Parameter's (schema) type. We call it `schema_type` because it is inside SchemaObj.
15
-
16
- Support all [data types](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#dataTypes) defined in OAS.
17
-
18
- In addition, you can use `format` in schema_info to define in fine detail the data type being used, like:
19
- int32, float, date ...
20
- All the types you can use as following:
21
- - **String, 'binary', 'base64'**
22
- - **Integer, Long, 'int32', 'int64', Float, Double**
23
- - **File** (it will be converted to `{ type: 'string', format: Config.file_format }`)
24
- - **Date, DateTime**
25
- - **Boolean**
26
- - **Array**: `Array[String]` or `[String]`
27
- - Nested Array: `[[[Integer]]]`
28
- - **Object**: you can use just `Object`, or use a hash to declare its properties `{ id!: Integer, name: String }`
29
- (`!` bang key means it is required).
30
- - Nested Object: `{ id!: Integer, name: { first: String, last: String } }`
31
- - Nested Array and Object: `[[{ id!: Integer, name: { first: String, last: String } }]]`
32
- - **:ComponentKey**: pass **Symbol** value to type will generate a Schema Reference Object link
33
- to the component correspond to ComponentKey, like: :IdPath, :NameQuery
34
-
35
- You can use `Object.const_set()` to define a constant that does not exist, but note that
36
- the value you set could not be a Symbol (it will be explained as a Ref Object), should be a String.
37
-
38
- #### required
39
- :opt or :req
40
-
41
- #### Schema Hash
42
-
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
- schema_info(optional) will be used to generate Schema Object inside Parameter Object.
45
- [source code](https://github.com/zhandao/zero-rails_openapi/blob/master/lib/oas_objs/schema_obj.rb)
46
- You can set the schema by following keys (all are optional), the words in parentheses are available aliases of the keys:
47
- - **enum (values, allowable_values)**
48
- Must be Array or Range(will be converted to Array)
49
- - **must_be (value, allowable_value)**
50
- Single value, could be a String, Array ...
51
- - **range (number_range)**
52
- Allow value in this continuous range. Set this field like this: `{ gt: 0, le: 5 }`
53
- - **length (lth)**
54
- Must be an Integer, Integer Array, Integer Range, or the following format Symbol: `:gt_`, `:ge_`, `:lt_`, `:le_`, examples: :ge_5 means "greater than or equal 5"; :lt_9 means "lower than 9".
55
- - **format (fmt)**
56
- - **is (is_a)**
57
- 1. It's not in OAS, just an addition field for better express.You can see it as `format`, but in fact they are quite different.
58
- 2. Look at this example: the `format` is set to "int32", but you also want to express that this
59
- schema is an "id" format —— this cannot be expressed in the current OAS version.
60
- 3. So I suggest that the value of `format` should related to data type, `is` should be an entity.
61
- 4. ZRO defaults to identify whether `is` patterns matched the name, then automatically generate `is`.
62
- for example the parameter name "user_email" will generate "is: email". Default `is` options are:
63
- [email phone password uuid uri url time date], to overwrite it you can set it in initializer `c.is_options = %w[]`.
64
- 5. If type is Object, for describing each property's schema, the only way is use ref type, like: `{ id: :Id, name: :Name }`
65
- - **pattern (regexp, pr, reg)**
66
- Regexp or Time Format
67
- - **default (dft, default_value)**
68
- - **as** # TODO
69
- - **example & examples** # TODO
@@ -1,39 +0,0 @@
1
- require 'oas_objs/schema_obj'
2
- require 'oas_objs/combined_schema'
3
- require 'oas_objs/param_obj'
4
- require 'oas_objs/response_obj'
5
- require 'oas_objs/request_body_obj'
6
- require 'oas_objs/ref_obj'
7
- require 'oas_objs/example_obj'
8
- require 'oas_objs/callback_obj'
9
- require 'open_api/dsl/helpers'
10
-
11
- module OpenApi
12
- module DSL
13
- module CommonDSL
14
- %i[ header header! path path! query query! cookie cookie! ].each do |param_type|
15
- define_method param_type do |*args|
16
- @necessity = param_type['!'] ? :req : :opt
17
- @param_type = param_type.to_s.delete('!') # OR: caller[0][/`.*'/][1..-2].to_sym
18
- _param_agent *args
19
- end
20
- end
21
-
22
- %i[ body body! ].each do |method|
23
- define_method method do |*args|
24
- @necessity = method['!'] ? :req : :opt
25
- _request_body_agent *args
26
- end
27
- end
28
-
29
- # `code`: when defining components, `code` means `component_key`
30
- def response code, desc, media_type = nil, data: { }, type: nil
31
- self[:responses][code] = ResponseObj.new(desc) unless (self[:responses] ||= { })[code].is_a?(ResponseObj)
32
- self[:responses][code].add_or_fusion(desc, media_type, { data: type || data })
33
- end
34
-
35
- alias_method :resp, :response
36
- alias_method :error, :response
37
- end
38
- end
39
- end
@@ -1,116 +0,0 @@
1
- require 'open_api/config'
2
- require 'colorize'
3
-
4
- module OpenApi
5
- module Generator
6
- module_function
7
-
8
- def self.included(base)
9
- base.extend ClassMethods
10
- end
11
-
12
- module ClassMethods
13
- def generate_docs(doc_name = nil)
14
- return puts ' ZRO'.red + ' No documents have been configured!' if Config.docs.keys.blank?
15
-
16
- # TODO
17
- # :nocov:
18
- Dir['./app/controllers/**/*_controller.rb'].each do |file|
19
- file.sub('./app/controllers/', '').sub('.rb', '').camelize.constantize
20
- end
21
- # :nocov:
22
- Dir[*Array(Config.doc_location)].each { |file| require file }
23
- (doc_name || Config.docs.keys).map { |name| { name => generate_doc(name) } }.reduce({ }, :merge!)
24
- end
25
-
26
- def generate_doc(doc_name)
27
- settings = Config.docs[doc_name]
28
- doc = { openapi: '3.0.0', **settings.slice(:info, :servers) }.merge!(
29
- security: settings[:global_security], tags: [ ], paths: { },
30
- components: {
31
- securitySchemes: settings[:securitySchemes] || { },
32
- schemas: { }, parameters: { }, requestBodies: { }
33
- }
34
- )
35
-
36
- [*(bdc = settings[:base_doc_classes]), *bdc.flat_map(&:descendants)].each do |ctrl|
37
- doc_info = ctrl.instance_variable_get('@doc_info')
38
- next if doc_info.nil?
39
-
40
- doc[:paths].merge!(ctrl.instance_variable_get('@api_info') || { })
41
- doc[:tags] << doc_info[:tag]
42
- doc[:components].deep_merge!(doc_info[:components] || { })
43
- OpenApi.routes_index[ctrl.instance_variable_get('@route_base')] = doc_name
44
- end
45
-
46
- doc[:components].delete_if { |_, v| v.blank? }
47
- doc[:tags] = doc[:tags].sort { |a, b| a[:name] <=> b[:name] }
48
- doc[:paths] = doc[:paths].sort.to_h
49
-
50
- OpenApi.docs[doc_name] = doc#.delete_if { |_, v| v.blank? }
51
- end
52
-
53
- def write_docs(generate_files: true)
54
- docs = generate_docs
55
- puts ' ZRO loaded.'.green if ENV['RAILS_ENV']
56
- return unless generate_files
57
- # :nocov:
58
- output_path = Config.file_output_path
59
- FileUtils.mkdir_p output_path
60
- max_length = docs.keys.map(&:size).sort.last
61
- docs.each do |doc_name, doc|
62
- puts ' ZRO'.green + " `#{doc_name.to_s.rjust(max_length)}.json` has been generated."
63
- File.open("#{output_path}/#{doc_name}.json", 'w') { |file| file.write JSON.pretty_generate doc }
64
- end
65
- # :nocov:
66
- end
67
- end
68
- # end of module
69
-
70
- def routes
71
- @routes ||=
72
- if (file = Config.rails_routes_file)
73
- File.read(file)
74
- else
75
- # :nocov:
76
- # ref https://github.com/rails/rails/blob/master/railties/lib/rails/tasks/routes.rake
77
- require './config/routes'
78
- all_routes = Rails.application.routes.routes
79
- require 'action_dispatch/routing/inspector'
80
- inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
81
- inspector.format(ActionDispatch::Routing::ConsoleFormatter.new, nil)
82
- # :nocov:
83
- end
84
- end
85
-
86
- def routes_list
87
- @routes_list ||= routes.split("\n").drop(1).map do |line|
88
- next unless line['#']
89
- infos = line.match(/[A-Z|].*/).to_s.split(' ') # => [GET, /api/v1/examples/:id, api/v1/examples#index]
90
-
91
- {
92
- http_verb: infos[0].downcase, # => "get" / "get|post"
93
- path: infos[1][0..-11].split('/').map do |item|
94
- item[':'] ? "{#{item[1..-1]}}" : item
95
- end.join('/'), # => "/api/v1/examples/{id}"
96
- action_path: infos[2] # => "api/v1/examples#index"
97
- } rescue next
98
- end.compact.group_by { |api| api[:action_path].split('#').first } # => { "api/v1/examples" => [..] }, group by paths
99
- end
100
-
101
- def get_actions_by_route_base(route_base)
102
- routes_list[route_base]&.map do |action_info|
103
- action_info[:action_path].split('#').last
104
- end
105
- end
106
-
107
- def find_path_httpverb_by(route_base, action)
108
- routes_list[route_base]&.map do |action_info|
109
- if action_info[:action_path].split('#').last == action.to_s
110
- return [ action_info[:path], action_info[:http_verb].split('|').first ]
111
- end
112
- end
113
- nil
114
- end
115
- end
116
- end