zero-rails_openapi 1.5.2 → 1.5.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/README_zh.md
CHANGED
@@ -27,6 +27,7 @@
|
|
27
27
|
- [安装](#installation)
|
28
28
|
- [配置](#configure)
|
29
29
|
- [DSL 介绍及用例](#usage---dsl)
|
30
|
+
- [基本的 DSL](#基本的-dsl)
|
30
31
|
- [用于 `api` 和 `api_dry` 块内的 DSL(描述 API 的参数、响应等)](#dsl-methods-inside-api-and-api_drys-block)
|
31
32
|
- [用于 `components` 块内的 DSL(描述可复用的组件)](#dsl-methods-inside-componentss-block-code-source)
|
32
33
|
- [执行文档生成](#run---generate-json-documentation-file)
|
@@ -47,8 +48,7 @@
|
|
47
48
|
|
48
49
|
你也可以看这份文档做初步的了解 [swagger.io](https://swagger.io/docs/specification/basic-structure/)
|
49
50
|
|
50
|
-
|
51
|
-
比如说 component(组件)—— 这能帮助你进一步减少书写文档 DSL 的代码(如果其中有很多可复用的数据结构的话)。
|
51
|
+
**建议你应该至少了解 OAS3 的基本结构**,比如说 component(组件)—— 这能帮助你进一步减少书写文档 DSL 的代码(如果其中有很多可复用的数据结构的话)。
|
52
52
|
|
53
53
|
## Installation
|
54
54
|
|
@@ -132,7 +132,7 @@
|
|
132
132
|
|
133
133
|
### DSL 使用实例
|
134
134
|
|
135
|
-
|
135
|
+
一个最简单的实例:
|
136
136
|
|
137
137
|
```ruby
|
138
138
|
class Api::ExamplesController < ApiController
|
@@ -143,10 +143,10 @@
|
|
143
143
|
end
|
144
144
|
```
|
145
145
|
|
146
|
-
|
147
|
-
[examples_controller.rb](documentation/examples/examples_controller.rb)
|
146
|
+
这有两份更详细的实例: [goods_doc.rb](documentation/examples/goods_doc.rb), 以及
|
147
|
+
[examples_controller.rb](documentation/examples/examples_controller.rb)。
|
148
148
|
|
149
|
-
###
|
149
|
+
### 基本的 DSL ([source code](lib/open_api/dsl.rb))
|
150
150
|
|
151
151
|
#### (1) `route_base` [无需调用,当且仅当你是在控制器中写文档时]
|
152
152
|
|
@@ -156,7 +156,7 @@
|
|
156
156
|
# usage
|
157
157
|
route_base 'api/v1/examples'
|
158
158
|
```
|
159
|
-
其默认设定为 `controller_path
|
159
|
+
其默认设定为 `controller_path`。
|
160
160
|
|
161
161
|
[这个技巧](#trick1---write-the-dsl-somewhere-else) 展示如何使用 `route_base` 来让你将 DSL 写在他处(与控制器分离),来简化你的控制器。
|
162
162
|
|
@@ -164,13 +164,14 @@
|
|
164
164
|
|
165
165
|
```ruby
|
166
166
|
# method signature
|
167
|
-
doc_tag(name: nil, desc: '', external_doc_url:
|
167
|
+
doc_tag(name: nil, desc: '', external_doc_url: nil)
|
168
168
|
# usage
|
169
|
-
doc_tag name: 'ExampleTagName', desc:
|
169
|
+
doc_tag name: 'ExampleTagName', desc: "ExamplesController's APIs"
|
170
170
|
```
|
171
|
-
|
172
|
-
|
173
|
-
|
171
|
+
该方法可以设置当前类中声明的 API 的 Tag
|
172
|
+
(Tag 是一个 [OpenApi Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#openapi-object)节点)。
|
173
|
+
|
174
|
+
Tag 的名字默认为 controller_name,除了名字,还可以设置可选参数 desc 和 external_doc_url。
|
174
175
|
|
175
176
|
#### (3) `components` [optional]
|
176
177
|
|
@@ -184,7 +185,7 @@
|
|
184
185
|
query! :UidQuery => [ :uid, String, desc: 'uid' ]
|
185
186
|
resp :BadRqResp => [ 'bad request', :json ]
|
186
187
|
end
|
187
|
-
|
188
|
+
|
188
189
|
# to use component
|
189
190
|
api :action, 'summary' do
|
190
191
|
query :doge, :DogSchema # to use a Schema component
|
@@ -192,15 +193,15 @@
|
|
192
193
|
response_ref :BadRqResp # to use a Response component
|
193
194
|
end
|
194
195
|
```
|
195
|
-
Component
|
196
|
-
|
197
|
-
|
198
|
-
|
196
|
+
Component 用以简化你的 DSL 代码 (即通过 `*_ref` 形式的方法,来引用已定义的 Component 对象)。
|
197
|
+
|
198
|
+
每个 RefObj 都是通过 component key 来关联指定的 component。
|
199
|
+
我们建议 component key 规范为驼峰命名法,且必须是 Symbol。
|
199
200
|
|
200
201
|
#### (4) `api_dry` [optional]
|
201
202
|
|
202
|
-
|
203
|
-
|
203
|
+
顾名思义,此方法用于 DRY。
|
204
|
+
|
204
205
|
```ruby
|
205
206
|
# method signature
|
206
207
|
api_dry(action = :all, desc = '', &block)
|
@@ -211,36 +212,33 @@
|
|
211
212
|
query! #...
|
212
213
|
end
|
213
214
|
```
|
214
|
-
|
215
|
-
|
216
|
-
|
215
|
+
|
216
|
+
如你所觉,传给该方法的块,将会 eval 到指定的 API 的**开头**。
|
217
|
+
|
217
218
|
#### (5) `api` [required]
|
218
219
|
|
219
|
-
|
220
|
-
|
220
|
+
定义指定 API (或者说是一个 controller action).
|
221
|
+
|
221
222
|
```ruby
|
222
223
|
# method signature
|
223
|
-
api(action, summary = '',
|
224
|
+
api(action, summary = '', http: nil, skip: [ ], use: [ ], &block)
|
224
225
|
# usage
|
225
|
-
api :index, '(SUMMARY) this api blah blah ...',
|
226
|
+
api :index, '(SUMMARY) this api blah blah ...', # block ...
|
226
227
|
```
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
`use` and `skip` options: to use or skip the parameters defined in `api_dry`.
|
232
|
-
|
228
|
+
|
229
|
+
`use` 和 `skip`: 指定使用或者跳过在 `api_dry` 中声明的参数。
|
230
|
+
|
233
231
|
```ruby
|
234
|
-
api :show, 'summary', use: [:id] #
|
232
|
+
api :show, 'summary', use: [:id] # 将会从 dry 块中声明的参数中挑出 id 这个参数用于 API :show
|
235
233
|
```
|
236
234
|
|
237
|
-
###
|
235
|
+
### 用于 [`api`]() 和 [`api_dry`]() 块内的 DSL
|
238
236
|
|
239
237
|
[source code](lib/open_api/dsl/api_info_obj.rb)
|
240
|
-
|
238
|
+
|
241
239
|
These following methods in the block describe the specified API action: description, valid?,
|
242
240
|
parameters, request body, responses, securities, servers.
|
243
|
-
|
241
|
+
|
244
242
|
(Here corresponds to OAS [Operation Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#operationObject))
|
245
243
|
|
246
244
|
#### (1) `this_api_is_invalid!`, its aliases:
|
@@ -256,7 +254,7 @@
|
|
256
254
|
# usage
|
257
255
|
this_api_is_invalid! 'this api is expired!'
|
258
256
|
```
|
259
|
-
|
257
|
+
|
260
258
|
Then `deprecated` of this API will be set to true.
|
261
259
|
|
262
260
|
#### (2) `desc`: description for the current API and its inputs (parameters and request body)
|
@@ -270,9 +268,9 @@
|
|
270
268
|
email: 'desc of the parameter :email'
|
271
269
|
```
|
272
270
|
|
273
|
-
You can of course describe the input in it's DSL method (like `query! :done ...`, [this line](https://github.com/zhandao/zero-rails_openapi
|
271
|
+
You can of course describe the input in it's DSL method (like `query! :done ...`, [this line](https://github.com/zhandao/zero-rails_openapi#dsl-usage-example)),
|
274
272
|
but that will make it long and ugly. We recommend that unite descriptions in this place.
|
275
|
-
|
273
|
+
|
276
274
|
In addition, when you want to dry the same parameters (each with a different description), it will be of great use.
|
277
275
|
|
278
276
|
#### (3) `param` family methods (OAS - [Parameter Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#parameterObject))
|
@@ -280,7 +278,7 @@
|
|
280
278
|
Define the parameters for the API (action).
|
281
279
|
```
|
282
280
|
param
|
283
|
-
param_ref # for reuse component,
|
281
|
+
param_ref # for reuse component,
|
284
282
|
# it links sepcified RefObjs (by component keys) to current parameters.
|
285
283
|
header, path, query, cookie # will pass specified parameter location to `param`
|
286
284
|
header!, path!, query!, cookie! # bang method of above methods
|
@@ -296,22 +294,22 @@
|
|
296
294
|
# `schema_type` is the type of parameter, like: String, Integer (must be a constant)
|
297
295
|
# For more explanation, please click the link below ↓↓↓
|
298
296
|
# method signature
|
299
|
-
param(param_type, param_name, schema_type, is_required,
|
297
|
+
param(param_type, param_name, schema_type, is_required, schema_info = { })
|
300
298
|
# usage
|
301
299
|
param :query, :page, Integer, :req, range: { gt: 0, le: 5 }, desc: 'page'
|
302
|
-
|
303
|
-
|
300
|
+
|
301
|
+
|
304
302
|
# method signature
|
305
303
|
param_ref(component_key, *component_keys) # should pass at least 1 key
|
306
304
|
# usage
|
307
305
|
param_ref :IdPath
|
308
306
|
param_ref :IdPath, :NameQuery, :TokenHeader
|
309
|
-
|
310
|
-
|
307
|
+
|
308
|
+
|
311
309
|
### method signature
|
312
|
-
header(param_name, schema_type = nil,
|
313
|
-
header!(param_name, schema_type = nil,
|
314
|
-
query!(param_name, schema_type = nil,
|
310
|
+
header(param_name, schema_type = nil, **schema_info)
|
311
|
+
header!(param_name, schema_type = nil, **schema_info)
|
312
|
+
query!(param_name, schema_type = nil, **schema_info)
|
315
313
|
# ...
|
316
314
|
### usage
|
317
315
|
header! 'Token', String
|
@@ -319,7 +317,7 @@
|
|
319
317
|
# The same effect as above, but not simple
|
320
318
|
param :query, :readed, Boolean, :req, must_be: true, default: false
|
321
319
|
#
|
322
|
-
# When schema_type is a Object
|
320
|
+
# When schema_type is a Object
|
323
321
|
# (describe by hash, key means prop's name, value means prop's schema_type)
|
324
322
|
query :good, { name: String, price: Float, spec: { size: String, weight: Integer } }, desc: 'good info'
|
325
323
|
# Or you can use `type:` to sign the schema_type, maybe this is clearer for describing object
|
@@ -342,8 +340,8 @@
|
|
342
340
|
query :search_type, String
|
343
341
|
query :search_val, String
|
344
342
|
query! :export, Boolean
|
345
|
-
|
346
|
-
|
343
|
+
|
344
|
+
|
347
345
|
# method signature
|
348
346
|
# `exp_by` (select_example_by): choose the example fields.
|
349
347
|
examples(exp_by = :all, examples_hash)
|
@@ -351,11 +349,11 @@
|
|
351
349
|
# it defines 2 examples by using parameter :id and :name
|
352
350
|
# if pass :all to `exp_by`, keys will be all the parameter's names.
|
353
351
|
examples [:id, :name], {
|
354
|
-
|
355
|
-
|
352
|
+
:right_input => [ 1, 'user'], # == { id: 1, name: 'user' }
|
353
|
+
:wrong_input => [ -1, '' ]
|
356
354
|
}
|
357
355
|
```
|
358
|
-
|
356
|
+
|
359
357
|
[This trick show you how to define combined schema (by using `one_of` ..)](#trick6---combined-schema-one-of--all-of--any-of--not)
|
360
358
|
|
361
359
|
[**>> More About `param` DSL <<**](documentation/parameter.md)
|
@@ -365,20 +363,22 @@
|
|
365
363
|
OpenAPI 3.0 uses the requestBody keyword to distinguish the payload from parameters.
|
366
364
|
```
|
367
365
|
request_body
|
368
|
-
body_ref # for reuse component,
|
366
|
+
body_ref # for reuse component,
|
369
367
|
# it links sepcified RefObjs (by component keys) to current body.
|
370
368
|
body, body! # alias of request_body
|
371
369
|
form, form! # define a multipart/form-data body
|
370
|
+
data # define [a] property in the form-data body
|
372
371
|
file, file! # define a File media-type body
|
373
372
|
```
|
374
|
-
|
373
|
+
Bang methods(!) means the specified media-type body is required.
|
374
|
+
|
375
375
|
```ruby
|
376
376
|
# method signature
|
377
|
-
request_body(
|
377
|
+
request_body(required, media_type, data: { }, **options)
|
378
378
|
# usage
|
379
|
-
|
380
|
-
#
|
381
|
-
request_body :opt, :form,
|
379
|
+
# (1) `data` contains all the attributes required by this request body.
|
380
|
+
# (2) `param_name!` means it is required, otherwise without '!' means optional.
|
381
|
+
request_body :opt, :form, data: { id!: Integer, name: { type: String, desc: 'name' } }, desc: 'form-data'
|
382
382
|
|
383
383
|
|
384
384
|
# method signature
|
@@ -388,96 +388,112 @@
|
|
388
388
|
|
389
389
|
|
390
390
|
# method signature
|
391
|
-
body!(media_type,
|
391
|
+
body!(media_type, data: { }, **options)
|
392
392
|
# usage
|
393
393
|
body :json
|
394
|
-
|
395
|
-
|
394
|
+
|
395
|
+
|
396
396
|
# method implement
|
397
|
-
def form
|
398
|
-
body :form,
|
397
|
+
def form data:, **options
|
398
|
+
body :form, data: data, **options
|
399
399
|
end
|
400
400
|
# usage
|
401
|
-
form!
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
401
|
+
form! data: {
|
402
|
+
name: String,
|
403
|
+
password: String,
|
404
|
+
password_confirmation: String
|
405
|
+
}
|
406
406
|
# advance usage
|
407
|
-
form
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
407
|
+
form data: {
|
408
|
+
:name! => { type: String, desc: 'user name' },
|
409
|
+
:password! => { type: String, pattern: /[0-9]{6,10}/, desc: 'password' },
|
410
|
+
# optional
|
411
|
+
:remarks => { type: String, desc: 'remarks' },
|
412
|
+
}, exp_by: %i[ name password ],
|
413
|
+
examples: { # ↓ ↓
|
414
|
+
:right_input => [ 'user1', '123456' ],
|
415
|
+
:wrong_input => [ 'user2', 'abc' ]
|
416
|
+
},
|
417
|
+
desc: 'for creating a user'
|
418
|
+
|
417
419
|
|
420
|
+
# method implement
|
421
|
+
def data name, type = nil, schema_info = { }
|
422
|
+
schema_info[:type] = type if type.present?
|
423
|
+
form data: { name => schema_info }
|
424
|
+
end
|
425
|
+
# usage: please look at the 4th point below
|
418
426
|
|
419
427
|
# about `file`
|
420
|
-
def file! media_type,
|
421
|
-
body! media_type,
|
428
|
+
def file! media_type, data: { type: File }, **options
|
429
|
+
body! media_type, data: data, **options
|
422
430
|
end
|
423
431
|
```
|
424
|
-
|
425
|
-
1.
|
426
|
-
|
427
|
-
|
428
|
-
2. `media_type`: we provide some [mapping](lib/oas_objs/media_type_obj.rb) from symbols to real media-types.
|
429
|
-
3. `schema_hash`: as above (see param).
|
430
|
-
**One thing that should be noted is: when use Hash writing, `scham_type` is writed in schema_hash using key :type.**
|
431
|
-
4. `exp_by` and `examples`: for the above example, the following has the same effect:
|
432
|
+
|
433
|
+
1. `media_type`: we provide some [mapping](lib/oas_objs/media_type_obj.rb) from symbols to real media-types.
|
434
|
+
2. `schema_info`: as above (see param).
|
435
|
+
3. `exp_by` and `examples`: for the above example, the following has the same effect:
|
432
436
|
```
|
433
437
|
examples: {
|
434
438
|
:right_input => { name: 'user1', password: '123456' },
|
435
439
|
:wrong_input => { name: 'user2', password: 'abc' }
|
436
440
|
}
|
437
441
|
```
|
438
|
-
|
442
|
+
4. *[IMPORTANT]* Each request bodies you declared will **FUSION** together. <a name="fusion"></a>
|
443
|
+
(1) Media-Types will be merged to `requestBody["content"]`
|
444
|
+
```ruby
|
445
|
+
form data: { }, desc: 'desc'
|
446
|
+
body :json, data: { }, desc: 'desc'
|
447
|
+
# will generate: "content": { "multipart/form-data": { }, "application/json": { } }
|
448
|
+
```
|
449
|
+
(2) The same media-types will fusion, but not merge:
|
450
|
+
(So that you can write `form` separately, and make `data` method possible.)
|
451
|
+
```ruby
|
452
|
+
data :param_a!, String
|
453
|
+
data :param_b, Integer
|
454
|
+
# or same as:
|
455
|
+
form data: { :param_a! => String }
|
456
|
+
form data: { :param_b => Integer }
|
457
|
+
# will generate: { "param_a": { "type": "string" }, "param_b": { "type": "integer" } } (call it X)
|
458
|
+
# therefore:
|
459
|
+
# "content": { "multipart/form-data":
|
460
|
+
# { "schema": { "type": "object", "properties": { X }, "required": [ "param_a" ] }
|
461
|
+
# }
|
462
|
+
```
|
463
|
+
|
439
464
|
#### (5) `response` family methods (OAS - [Response Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#response-object))
|
440
|
-
|
465
|
+
|
441
466
|
Define the responses for the API (action).
|
442
467
|
```
|
443
|
-
response
|
468
|
+
response # aliases: `resp` and `error`
|
444
469
|
response_ref
|
445
|
-
default_response or dft_resp
|
446
|
-
error_response, other_response, oth_resp, error, err_resp # response's aliases, should be used in the error response context.
|
447
|
-
merge_to_resp
|
448
470
|
```
|
449
|
-
|
471
|
+
|
450
472
|
```ruby
|
451
473
|
# method signature
|
452
|
-
response(
|
474
|
+
response(code, desc, media_type = nil, data: { }, type: nil)
|
453
475
|
# usage
|
476
|
+
resp 200, 'json response', :json, data: { name: 'test' }
|
454
477
|
response 200, 'query result', :pdf, type: File
|
478
|
+
# same as:
|
479
|
+
response 200, 'query result', :pdf, data: File
|
455
480
|
|
456
481
|
# method signature
|
457
482
|
response_ref(code_compkey_hash)
|
458
483
|
# usage
|
459
484
|
response_ref 700 => :AResp, 800 => :BResp
|
460
|
-
|
461
|
-
# method signature
|
462
|
-
merge_to_resp(code, by:)
|
463
|
-
# usage
|
464
|
-
merge_to_resp 200, by: {
|
465
|
-
data: {
|
466
|
-
type: String
|
467
|
-
}
|
468
|
-
}
|
469
485
|
```
|
470
|
-
|
471
|
-
**practice:**
|
472
|
-
|
486
|
+
|
487
|
+
**practice:** Automatically generate responses based on the agreed error class. [AutoGenDoc](documentation/examples/auto_gen_doc.rb#L63)
|
488
|
+
|
473
489
|
#### (6) Authentication and Authorization
|
474
|
-
|
475
|
-
First of all, please make sure that you have read one of the following documents:
|
476
|
-
[OpenApi Auth](https://swagger.io/docs/specification/authentication/)
|
490
|
+
|
491
|
+
First of all, please make sure that you have read one of the following documents:
|
492
|
+
[OpenApi Auth](https://swagger.io/docs/specification/authentication/)
|
477
493
|
or [securitySchemeObject](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securitySchemeObject)
|
478
|
-
|
494
|
+
|
479
495
|
##### Define Security Scheme
|
480
|
-
|
496
|
+
|
481
497
|
Use these DSL in your initializer or `components` block:
|
482
498
|
```
|
483
499
|
security_scheme # alias `auth_scheme`
|
@@ -491,7 +507,7 @@
|
|
491
507
|
security_scheme(scheme_name, other_info)
|
492
508
|
# usage
|
493
509
|
security_scheme :BasicAuth, { type: 'http', scheme: 'basic', desc: 'basic auth' }
|
494
|
-
|
510
|
+
|
495
511
|
# method signature
|
496
512
|
base_auth(scheme_name, other_info = { })
|
497
513
|
bearer_auth(scheme_name, format = 'JWT', other_info = { })
|
@@ -501,16 +517,16 @@
|
|
501
517
|
bearer_auth :Token
|
502
518
|
api_key :ApiKeyAuth, field: 'X-API-Key', in: 'header', desc: 'pass api key to header'
|
503
519
|
```
|
504
|
-
|
520
|
+
|
505
521
|
##### Apply Security
|
506
|
-
|
522
|
+
|
507
523
|
```
|
508
524
|
# In initializer
|
509
525
|
# Global effectiveness
|
510
526
|
global_security_require
|
511
527
|
global_security # alias
|
512
528
|
global_auth # alias
|
513
|
-
|
529
|
+
|
514
530
|
# In `api`'s block
|
515
531
|
# Only valid for the current controller
|
516
532
|
security_require
|
@@ -529,42 +545,42 @@
|
|
529
545
|
```
|
530
546
|
|
531
547
|
#### (7) Overriding Global Servers by `server`
|
532
|
-
|
548
|
+
|
533
549
|
```ruby
|
534
550
|
# method signature
|
535
|
-
server(url, desc)
|
551
|
+
server(url, desc: '')
|
536
552
|
# usage
|
537
|
-
server 'http://localhost:3000', 'local'
|
553
|
+
server 'http://localhost:3000', desc: 'local'
|
538
554
|
```
|
539
|
-
|
555
|
+
|
540
556
|
### DSL methods inside [components]()'s block ([code source](lib/open_api/dsl/components.rb))
|
541
557
|
|
542
558
|
(Here corresponds to OAS [Components Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md#componentsObject))
|
543
|
-
|
559
|
+
|
544
560
|
Inside `components`'s block,
|
545
561
|
you can use the same DSL as [[DSL methods inside `api` and `api_dry`'s block]](#dsl-methods-inside-api-and-api_drys-block).
|
546
|
-
But there are two differences:
|
547
|
-
|
562
|
+
But there are two differences:
|
563
|
+
|
548
564
|
(1) Each method needs to pass one more parameter `component_key`
|
549
565
|
(in the first parameter position),
|
550
566
|
this will be used as the reference name for the component.
|
551
|
-
|
567
|
+
|
552
568
|
```ruby
|
553
569
|
query! :UidQuery, :uid, String
|
554
570
|
```
|
555
|
-
This writing is feasible but not recommended,
|
571
|
+
This writing is feasible but not recommended,
|
556
572
|
because component's key and parameter's name seem easy to confuse.
|
557
573
|
The recommended writing is:
|
558
|
-
|
574
|
+
|
559
575
|
```ruby
|
560
576
|
query! :UidQuery => [:uid, String]
|
561
577
|
```
|
562
|
-
|
578
|
+
|
563
579
|
(2) You can use `schema` to define a Schema Component.
|
564
|
-
|
580
|
+
|
565
581
|
```ruby
|
566
582
|
# method signature
|
567
|
-
schema(component_key, type = nil,
|
583
|
+
schema(component_key, type = nil, **schema_info)
|
568
584
|
# usage
|
569
585
|
schema :Dog => [ String, desc: 'dogee' ] # <= schema_type is `String`
|
570
586
|
# advance usage
|
@@ -588,22 +604,22 @@
|
|
588
604
|
## Run! - Generate JSON Documentation File
|
589
605
|
|
590
606
|
Use `OpenApi.write_docs`:
|
591
|
-
|
607
|
+
|
592
608
|
```ruby
|
593
609
|
# initializer
|
594
610
|
OpenApi.write_docs generate_files: !Rails.env.production?
|
595
|
-
|
611
|
+
|
596
612
|
# or run directly in console
|
597
613
|
OpenApi.write_docs # will generate json doc files
|
598
614
|
```
|
599
|
-
|
615
|
+
|
600
616
|
Then the JSON files will be written to the directories you set. (Each API a file.)
|
601
617
|
|
602
618
|
## Use Swagger UI(very beautiful web page) to show your Documentation
|
603
619
|
|
604
|
-
Download [Swagger UI](https://github.com/swagger-api/swagger-ui) (version >= 2.3.0 support the OAS3)
|
605
|
-
to your project,
|
606
|
-
change the default JSON file path(url) in index.html.
|
620
|
+
Download [Swagger UI](https://github.com/swagger-api/swagger-ui) (version >= 2.3.0 support the OAS3)
|
621
|
+
to your project,
|
622
|
+
change the default JSON file path(url) in index.html.
|
607
623
|
In order to use it, you may have to enable CORS, [see](https://github.com/swagger-api/swagger-ui#cors-support)
|
608
624
|
|
609
625
|
## Tricks
|
@@ -613,39 +629,39 @@
|
|
613
629
|
Does your documentation take too many lines?
|
614
630
|
Do you want to separate documentation from business controller to simplify both?
|
615
631
|
Very easy! Just follow
|
616
|
-
|
632
|
+
|
617
633
|
```ruby
|
618
634
|
# config/initializers/open_api.rb
|
619
635
|
# in your configuration
|
620
636
|
base_doc_class: ApiDoc
|
621
|
-
|
637
|
+
|
622
638
|
# app/api_doc/api_doc.rb
|
623
639
|
require 'open_api/dsl'
|
624
|
-
|
640
|
+
|
625
641
|
class ApiDoc < Object
|
626
642
|
include OpenApi::DSL
|
627
643
|
end
|
628
|
-
|
644
|
+
|
629
645
|
# app/api_doc/v1/examples_doc.rb
|
630
646
|
class V1::ExamplesDoc < ApiDoc
|
631
647
|
route_base 'api/v1/examples'
|
632
|
-
|
648
|
+
|
633
649
|
api :index do
|
634
650
|
# ...
|
635
651
|
end
|
636
652
|
end
|
637
653
|
```
|
638
|
-
|
654
|
+
|
639
655
|
Notes: file name ends in `_doc.rb` by default, but you can change via `Config.doc_location`
|
640
|
-
|
656
|
+
(it should be file paths, defaults to `./app/**/*_doc.rb`).
|
641
657
|
|
642
658
|
### Trick2 - Global DRYing
|
643
659
|
|
644
660
|
Method `api_dry` is for DRY but its scope is limited to the current controller.
|
645
|
-
|
661
|
+
|
646
662
|
I have no idea of best practices, But you can look at this [file](documentation/examples/auto_gen_doc.rb).
|
647
663
|
The implementation of the file is: do `api_dry` when inherits the base controller inside `inherited` method.
|
648
|
-
|
664
|
+
|
649
665
|
You can use `sort` to specify the order of parameters.
|
650
666
|
|
651
667
|
### Trick3 - Auto Generate Description
|
@@ -654,22 +670,22 @@
|
|
654
670
|
desc 'api desc',
|
655
671
|
search_type!: 'search field, allows:<br/>'
|
656
672
|
query :search_type, String, enum: %w[name creator category price]
|
657
|
-
|
673
|
+
|
658
674
|
# or
|
659
|
-
|
675
|
+
|
660
676
|
query :search_type, String, desc!: 'search field, allows:<br/>',
|
661
677
|
enum: %w[name creator category price]
|
662
678
|
```
|
663
|
-
|
679
|
+
|
664
680
|
Notice `!` use (`search_type!`, `desc!`), it tells ZRO to append
|
665
681
|
information that analyzed from definitions (enum, must_be ..) to description automatically.
|
666
|
-
|
667
|
-
Any one of above will generate:
|
682
|
+
|
683
|
+
Any one of above will generate:
|
668
684
|
> search field, allows:<br/>1/ name<br/>2/ creator,<br/>3/ category<br/>4/ price<br/>
|
669
|
-
|
685
|
+
|
670
686
|
You can also use Hash to define `enum`:
|
671
687
|
```ruby
|
672
|
-
query :view, String, desc: 'allows values<br/>', enum
|
688
|
+
query :view, String, desc: 'allows values<br/>', enum!: {
|
673
689
|
'all goods (default)': :all,
|
674
690
|
'only online': :online,
|
675
691
|
'only offline': :offline,
|
@@ -683,29 +699,29 @@
|
|
683
699
|
|
684
700
|
Pass `skip: []` and `use: []` to `api` like following code:
|
685
701
|
```ruby
|
686
|
-
api :index, 'desc',
|
702
|
+
api :index, 'desc', skip: [ :Token ]
|
687
703
|
```
|
688
|
-
|
704
|
+
|
689
705
|
Look at this [file](documentation/examples/goods_doc.rb) to learn more.
|
690
706
|
|
691
707
|
### Trick5 - Auto Generate index/show Actions's Response-Types Based on DB Schema
|
692
708
|
|
693
709
|
Use method `load_schema` in `api_dry`.
|
694
|
-
|
710
|
+
|
695
711
|
See this [file](documentation/examples/auto_gen_doc.rb#L51) for uasge information.
|
696
712
|
|
697
713
|
### Trick6 - Combined Schema (one_of / all_of / any_of / not)
|
698
714
|
|
699
715
|
```ruby
|
700
|
-
query :combination, one_of: [ :GoodSchema, String, { type: Integer, desc: 'integer input'}]
|
701
|
-
|
702
|
-
form
|
716
|
+
query :combination, one_of: [ :GoodSchema, String, { type: Integer, desc: 'integer input' } ]
|
717
|
+
|
718
|
+
form data: {
|
703
719
|
:combination_in_form => { any_of: [ Integer, String ] }
|
704
720
|
}
|
705
|
-
|
721
|
+
|
706
722
|
schema :PetSchema => [ not: [ Integer, Boolean ] ]
|
707
723
|
```
|
708
|
-
|
724
|
+
|
709
725
|
OAS: [link1](https://swagger.io/docs/specification/data-models/oneof-anyof-allof-not/),
|
710
726
|
[link2](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaObject)
|
711
727
|
|
@@ -714,7 +730,7 @@
|
|
714
730
|
- **You wrote document of the current API, but not find in the generated json file?**
|
715
731
|
Check your routing settings.
|
716
732
|
- **Undefine method `match?`**
|
717
|
-
Monkey patches for `String` and `Symbol`:
|
733
|
+
Monkey patches for `String` and `Symbol`:
|
718
734
|
```ruby
|
719
735
|
class String # Symbol
|
720
736
|
def match?(pattern); !match(pattern).nil? end
|
@@ -722,7 +738,7 @@
|
|
722
738
|
```
|
723
739
|
- **Report error when require `routes.rb`?***
|
724
740
|
1. Run `rails routes`.
|
725
|
-
2. Copy the output to a file, for example `config/routes.txt`.
|
741
|
+
2. Copy the output to a file, for example `config/routes.txt`.
|
726
742
|
Ignore the file `config/routes.txt`.
|
727
743
|
3. Put `c.rails_routes_file = 'config/routes.txt'` to your ZRO config.
|
728
744
|
|
@@ -730,10 +746,10 @@
|
|
730
746
|
## About `OpenApi.docs` and `OpenApi.routes_index`
|
731
747
|
|
732
748
|
After `OpenApi.write_docs`, the above two module variables will be generated.
|
733
|
-
|
749
|
+
|
734
750
|
`OpenApi.docs`: A Hash with API names as keys, and documents of each APIs as values.
|
735
751
|
documents are instances of ActiveSupport::HashWithIndifferentAccess.
|
736
|
-
|
752
|
+
|
737
753
|
`OpenApi.routes_index`: Inverted index of controller path to API name mappings.
|
738
754
|
Like: `{ 'api/v1/examples' => :homepage_api }`
|
739
755
|
It's useful when you want to look up a document based on a controller and do something.
|
@@ -741,7 +757,7 @@
|
|
741
757
|
## Development
|
742
758
|
|
743
759
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
744
|
-
|
760
|
+
|
745
761
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
746
762
|
|
747
763
|
## License
|