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
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
|