serverless-openapi-documenter 0.0.31 → 0.0.33
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.
- package/README.md +164 -11
- package/package.json +2 -2
- package/src/definitionGenerator.js +184 -0
- package/test/unit/definitionGenerator.spec.js +477 -1
package/README.md
CHANGED
|
@@ -59,8 +59,16 @@ Options:
|
|
|
59
59
|
| info.title | custom.documentation.title OR service |
|
|
60
60
|
| info.description | custom.documentation.description OR blank string |
|
|
61
61
|
| info.version | custom.documentation.version OR random v4 uuid if not provided |
|
|
62
|
+
| info.termsOfService | custom.documentation.termsOfService |
|
|
63
|
+
| info.contact | custom.documentation.contact |
|
|
64
|
+
| info.contact.name | custom.documentation.contact.name OR blank string |
|
|
65
|
+
| info.contact.url | custom.documentation.contact.url if provided |
|
|
66
|
+
| info.license | custom.documentation.license |
|
|
67
|
+
| info.license.name | custom.documentation.license.name OR blank string |
|
|
68
|
+
| info.license.url | custom.documentation.license.url if provided |
|
|
62
69
|
| externalDocs.description | custom.documentation.externalDocumentation.description |
|
|
63
70
|
| externalDocs.url | custom.documentation.externalDocumentation.url |
|
|
71
|
+
| security | custom.documentation.security |
|
|
64
72
|
| servers[].description | custom.documentation.servers.description |
|
|
65
73
|
| servers[].url | custom.documentation.servers.url |
|
|
66
74
|
| servers[].variables | custom.documentation.servers.variables |
|
|
@@ -82,6 +90,7 @@ Options:
|
|
|
82
90
|
| path[path].[operation].externalDocs.url | functions.functions.[http OR httpApi].documentation.externalDocumentation.url |
|
|
83
91
|
| path[path].[operation].servers[].description | functions.functions.[http OR httpApi].documentation.servers.description |
|
|
84
92
|
| path[path].[operation].servers[].url | functions.functions.[http OR httpApi].documentation.servers.url |
|
|
93
|
+
| path[path].[operation].security | functions.functions.[http OR httpApi].documentation.security |
|
|
85
94
|
| path[path].[operation].deprecated | functions.functions.[http OR httpApi].documentation.deprecated |
|
|
86
95
|
| path[path].[operation].parameters | functions.functions.[http OR httpApi].documentation.[path/query/cookie/header]Params |
|
|
87
96
|
| path[path].[operation].parameters.name | functions.functions.[http OR httpApi].documentation.[path/query/cookie/header]Params.name |
|
|
@@ -118,6 +127,7 @@ custom:
|
|
|
118
127
|
version: '1'
|
|
119
128
|
title: 'My API'
|
|
120
129
|
description: 'This is my API'
|
|
130
|
+
termsOfService: https://google.com
|
|
121
131
|
externalDocumentation:
|
|
122
132
|
url: https://google.com
|
|
123
133
|
description: A link to google
|
|
@@ -126,7 +136,7 @@ custom:
|
|
|
126
136
|
description: The server
|
|
127
137
|
variables:
|
|
128
138
|
port:
|
|
129
|
-
enum:
|
|
139
|
+
enum:
|
|
130
140
|
- 4000
|
|
131
141
|
- 3000
|
|
132
142
|
default: 3000
|
|
@@ -142,6 +152,58 @@ custom:
|
|
|
142
152
|
|
|
143
153
|
Mostly everything here is optional. A version from a UUID will be generated for you if you don't specify one, title will be the name of your service if you don't specify one.
|
|
144
154
|
|
|
155
|
+
#### termsOfService
|
|
156
|
+
|
|
157
|
+
Must be in the format of a url if included.
|
|
158
|
+
|
|
159
|
+
#### Contact
|
|
160
|
+
|
|
161
|
+
You can provide an optional contact object such as:
|
|
162
|
+
|
|
163
|
+
```yml
|
|
164
|
+
custom:
|
|
165
|
+
documentation:
|
|
166
|
+
contact:
|
|
167
|
+
name: John
|
|
168
|
+
url: https://example.com
|
|
169
|
+
email: John@example.com
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
These fields are optional, though `url` and `email` need to be in the format of an email address (ed: what that might be, i'm not 100% sure... go read the email RFC(s)) and a url.
|
|
173
|
+
|
|
174
|
+
#### License
|
|
175
|
+
|
|
176
|
+
You can provide an optional license object such as:
|
|
177
|
+
|
|
178
|
+
```yml
|
|
179
|
+
custom:
|
|
180
|
+
documentation:
|
|
181
|
+
license:
|
|
182
|
+
name: Apache 2.0
|
|
183
|
+
url: https://www.apache.org/licenses/LICENSE-2.0.html
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Name is required but `url` is optional and must be in the format of a url.
|
|
187
|
+
#### Extended Fields
|
|
188
|
+
|
|
189
|
+
You can also add extended fields to the documentation object:
|
|
190
|
+
|
|
191
|
+
```yml
|
|
192
|
+
custom:
|
|
193
|
+
documentation:
|
|
194
|
+
x-other-field: This is an extended field
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
These fields must have `x-` before them, otherwise they will be ignored:
|
|
198
|
+
|
|
199
|
+
```yml
|
|
200
|
+
custom:
|
|
201
|
+
documentation:
|
|
202
|
+
other-field: This is an extended field
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`other-field` here will not make it to the generated OpenAPI schema.
|
|
206
|
+
|
|
145
207
|
These configurations can be quite verbose; you can separate it out into it's own file, such as `serverless.doc.yml` as below:
|
|
146
208
|
|
|
147
209
|
```yml
|
|
@@ -159,6 +221,40 @@ functions:
|
|
|
159
221
|
|
|
160
222
|
For more info on `serverless.yml` syntax, see their docs.
|
|
161
223
|
|
|
224
|
+
#### securitySchemes
|
|
225
|
+
|
|
226
|
+
You can provide optional Security Schemes:
|
|
227
|
+
|
|
228
|
+
```yml
|
|
229
|
+
custom:
|
|
230
|
+
documentation:
|
|
231
|
+
securitySchemes:
|
|
232
|
+
my_api_key:
|
|
233
|
+
type: apiKey
|
|
234
|
+
name: api_key
|
|
235
|
+
in: header
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
It accepts all available Security Schemes and follows the specification: https://spec.openapis.org/oas/v3.0.3#security-scheme-object
|
|
239
|
+
|
|
240
|
+
#### Security on each operation
|
|
241
|
+
|
|
242
|
+
To apply an overall security scheme to all of your operations without having to add the documentation to each one, you can write it like:
|
|
243
|
+
|
|
244
|
+
```yml
|
|
245
|
+
custom:
|
|
246
|
+
documentation:
|
|
247
|
+
securitySchemes:
|
|
248
|
+
my_api_key:
|
|
249
|
+
type: apiKey
|
|
250
|
+
name: api_key
|
|
251
|
+
in: header
|
|
252
|
+
security:
|
|
253
|
+
- my_api_key: []
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
This will apply the requirement of each operation requiring your `my_api_key` security scheme, [you can override this](#security).
|
|
257
|
+
|
|
162
258
|
#### Models
|
|
163
259
|
|
|
164
260
|
There are two ways to write the Models. Models contain additional information that you can use to define schemas for endpoints. You must define the *content type* for each schema that you provide in the models.
|
|
@@ -244,20 +340,20 @@ custom:
|
|
|
244
340
|
content:
|
|
245
341
|
application/json:
|
|
246
342
|
schema: &ErrorItem
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
343
|
+
type: object
|
|
344
|
+
properties:
|
|
345
|
+
message:
|
|
346
|
+
type: string
|
|
347
|
+
code:
|
|
348
|
+
type: integer
|
|
349
|
+
|
|
254
350
|
- name: "PutDocumentResponse"
|
|
255
351
|
description: "PUT Document response model (external reference example)"
|
|
256
352
|
content:
|
|
257
353
|
application/json:
|
|
258
|
-
schema:
|
|
259
|
-
|
|
260
|
-
|
|
354
|
+
schema:
|
|
355
|
+
type: array
|
|
356
|
+
items: *ErrorItem
|
|
261
357
|
```
|
|
262
358
|
|
|
263
359
|
`&ErrorItem` in the above example creates a node anchor (&ErrorItem) to the `ErrorResponse` schema which then can be used in the `PutDocumentResponse` schema via the reference (*ErrorItem). The node anchor needs to be declared first before it can be used elsewhere via the reference, swapping the above example around would result in an error.
|
|
@@ -280,6 +376,7 @@ The `documentation` section of the event configuration can contain the following
|
|
|
280
376
|
* `pathParams`: a list of path parameters (see [pathParams](#pathparams) below)
|
|
281
377
|
* `cookieParams`: a list of cookie parameters (see [cookieParams](#cookieparams) below)
|
|
282
378
|
* `headerParams`: a list of headers (see [headerParams](#headerparams---request-headers) below)
|
|
379
|
+
* `security`: The security requirement to apply (see [security](#security) below)
|
|
283
380
|
* `methodResponses`: an array of response models and applicable status codes
|
|
284
381
|
* `statusCode`: applicable http status code (ie. 200/404/500 etc.)
|
|
285
382
|
* `responseBody`: contains description of the response
|
|
@@ -420,6 +517,62 @@ headerParams:
|
|
|
420
517
|
type: "string"
|
|
421
518
|
```
|
|
422
519
|
|
|
520
|
+
#### `security`
|
|
521
|
+
|
|
522
|
+
The `security` property allows you to specify the [Security Scheme](#securityschemes) to apply to the HTTP Request. If you have applied an `security` ([see Security on each operation](#security-on-each-operation)) then you can either leave this field off, or to override it with a different scheme you can write it like:
|
|
523
|
+
|
|
524
|
+
```yml
|
|
525
|
+
custom:
|
|
526
|
+
documentation:
|
|
527
|
+
securitySchemes:
|
|
528
|
+
my_api_key:
|
|
529
|
+
type: apiKey
|
|
530
|
+
name: api_key
|
|
531
|
+
in: header
|
|
532
|
+
petstore_auth:
|
|
533
|
+
type: oauth2
|
|
534
|
+
flows:
|
|
535
|
+
implicit:
|
|
536
|
+
authorizationUrl: https://example.com/api/oauth/dialog
|
|
537
|
+
scopes:
|
|
538
|
+
write:pets: modify pets in your account
|
|
539
|
+
read:pets: read your pets
|
|
540
|
+
security:
|
|
541
|
+
- my_api_key: []
|
|
542
|
+
|
|
543
|
+
functions:
|
|
544
|
+
getData:
|
|
545
|
+
events:
|
|
546
|
+
- http:
|
|
547
|
+
documentation:
|
|
548
|
+
security:
|
|
549
|
+
- petstore_auth:
|
|
550
|
+
- write:pets
|
|
551
|
+
- read:pets
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
If you have specified an `security` at the document root, but this HTTP Request should not apply any security schemes, you should set security to be an array with an empty object:
|
|
555
|
+
|
|
556
|
+
```yml
|
|
557
|
+
custom:
|
|
558
|
+
documentation:
|
|
559
|
+
securitySchemes:
|
|
560
|
+
my_api_key:
|
|
561
|
+
type: apiKey
|
|
562
|
+
name: api_key
|
|
563
|
+
in: header
|
|
564
|
+
security:
|
|
565
|
+
- my_api_key: []
|
|
566
|
+
|
|
567
|
+
functions:
|
|
568
|
+
getData:
|
|
569
|
+
events:
|
|
570
|
+
- http:
|
|
571
|
+
documentation:
|
|
572
|
+
security:
|
|
573
|
+
- {}
|
|
574
|
+
```
|
|
575
|
+
|
|
423
576
|
#### `requestModels`
|
|
424
577
|
|
|
425
578
|
The `requestModels` property allows you to define models for the HTTP Request of the function event. You can define a different model for each different `Content-Type`. You can define a reference to the relevant request model named in the `models` section of your configuration (see [Defining Models](#models) section).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "serverless-openapi-documenter",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.33",
|
|
4
4
|
"description": "Generate OpenAPI v3 documentation and Postman Collections from your Serverless Config",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"chai": "^4.3.7",
|
|
45
|
-
"mocha": "^10.
|
|
45
|
+
"mocha": "^10.2.0",
|
|
46
46
|
"sinon": "^15.0.0"
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -39,6 +39,15 @@ class DefinitionGenerator {
|
|
|
39
39
|
|
|
40
40
|
async parse() {
|
|
41
41
|
this.createInfo()
|
|
42
|
+
|
|
43
|
+
if (this.serverless.service.custom.documentation.securitySchemes) {
|
|
44
|
+
this.createSecuritySchemes(this.serverless.service.custom.documentation.securitySchemes)
|
|
45
|
+
|
|
46
|
+
if (this.serverless.service.custom.documentation.security) {
|
|
47
|
+
this.openAPI.security = this.serverless.service.custom.documentation.security
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
42
51
|
await this.createPaths()
|
|
43
52
|
.catch(err => {
|
|
44
53
|
throw err
|
|
@@ -68,6 +77,37 @@ class DefinitionGenerator {
|
|
|
68
77
|
description: documentation?.description || '',
|
|
69
78
|
version: documentation?.version || uuid(),
|
|
70
79
|
}
|
|
80
|
+
|
|
81
|
+
if (documentation.termsOfService)
|
|
82
|
+
info.termsOfService = documentation.termsOfService
|
|
83
|
+
|
|
84
|
+
if (documentation.contact) {
|
|
85
|
+
const contactObj = {}
|
|
86
|
+
contactObj.name = documentation.contact.name || ''
|
|
87
|
+
|
|
88
|
+
if (documentation.contact.url)
|
|
89
|
+
contactObj.url = documentation.contact.url
|
|
90
|
+
|
|
91
|
+
contactObj.email = documentation.contact.email || ''
|
|
92
|
+
Object.assign(info, {contact: contactObj})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (documentation.license && documentation.license.name) {
|
|
96
|
+
const licenseObj = {}
|
|
97
|
+
licenseObj.name = documentation.license.name || ''
|
|
98
|
+
|
|
99
|
+
if (documentation.license.url)
|
|
100
|
+
licenseObj.url = documentation.license.url || ''
|
|
101
|
+
|
|
102
|
+
Object.assign(info, {license: licenseObj})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for (const key of Object.keys(documentation)) {
|
|
106
|
+
if (/^[x\-]/i.test(key)) {
|
|
107
|
+
Object.assign(info, {[key]: documentation[key]})
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
71
111
|
Object.assign(this.openAPI, {info})
|
|
72
112
|
}
|
|
73
113
|
|
|
@@ -234,6 +274,10 @@ class DefinitionGenerator {
|
|
|
234
274
|
obj.externalDocs = documentation.externalDocumentation
|
|
235
275
|
}
|
|
236
276
|
|
|
277
|
+
if (Object.keys(documentation).includes('security')) {
|
|
278
|
+
obj.security = documentation.security
|
|
279
|
+
}
|
|
280
|
+
|
|
237
281
|
if (Object.keys(documentation).includes('deprecated'))
|
|
238
282
|
obj.deprecated = documentation.deprecated
|
|
239
283
|
|
|
@@ -492,6 +536,146 @@ class DefinitionGenerator {
|
|
|
492
536
|
}
|
|
493
537
|
}
|
|
494
538
|
|
|
539
|
+
addToComponents(type, schema, name) {
|
|
540
|
+
const schemaObj = {
|
|
541
|
+
[name]: schema
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (this.openAPI?.components) {
|
|
545
|
+
if (this.openAPI.components[type]) {
|
|
546
|
+
Object.assign(this.openAPI.components[type], schemaObj)
|
|
547
|
+
} else {
|
|
548
|
+
Object.assign(this.openAPI.components, {[type]: schemaObj})
|
|
549
|
+
}
|
|
550
|
+
} else {
|
|
551
|
+
const components = {
|
|
552
|
+
components: {
|
|
553
|
+
[type]: schemaObj
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
Object.assign(this.openAPI, components)
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
createSecuritySchemes(securitySchemes) {
|
|
562
|
+
for (const scheme of Object.keys(securitySchemes)) {
|
|
563
|
+
const securityScheme = securitySchemes[scheme]
|
|
564
|
+
const schema = {}
|
|
565
|
+
|
|
566
|
+
if (securityScheme.description)
|
|
567
|
+
schema.description = securityScheme.description
|
|
568
|
+
|
|
569
|
+
switch(securityScheme.type.toLowerCase()) {
|
|
570
|
+
case 'apikey':
|
|
571
|
+
const apiKeyScheme = this.createAPIKeyScheme(securityScheme)
|
|
572
|
+
schema.type = 'apiKey'
|
|
573
|
+
Object.assign(schema, apiKeyScheme)
|
|
574
|
+
break;
|
|
575
|
+
|
|
576
|
+
case 'http':
|
|
577
|
+
const HTTPScheme = this.createHTTPScheme(securityScheme)
|
|
578
|
+
schema.type = 'http'
|
|
579
|
+
Object.assign(schema, HTTPScheme)
|
|
580
|
+
break;
|
|
581
|
+
|
|
582
|
+
case 'openidconnect':
|
|
583
|
+
const openIdConnectScheme = this.createOpenIDConnectScheme(securityScheme)
|
|
584
|
+
schema.type = 'openIdConnect'
|
|
585
|
+
Object.assign(schema, openIdConnectScheme)
|
|
586
|
+
break;
|
|
587
|
+
|
|
588
|
+
case 'oauth2':
|
|
589
|
+
const oAuth2Scheme = this.createOAuth2Scheme(securityScheme)
|
|
590
|
+
schema.type = 'oauth2'
|
|
591
|
+
Object.assign(schema, oAuth2Scheme)
|
|
592
|
+
break;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
this.addToComponents('securitySchemes', schema, scheme)
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
createAPIKeyScheme(securitySchema) {
|
|
600
|
+
const schema = {}
|
|
601
|
+
if (securitySchema.name)
|
|
602
|
+
schema.name = securitySchema.name
|
|
603
|
+
else
|
|
604
|
+
throw new Error('Security Scheme for "apiKey" requires the name of the header, query or cookie parameter to be used')
|
|
605
|
+
|
|
606
|
+
if (securitySchema.in)
|
|
607
|
+
schema.in = securitySchema.in
|
|
608
|
+
else
|
|
609
|
+
throw new Error('Security Scheme for "apiKey" requires the location of the API key: header, query or cookie parameter')
|
|
610
|
+
|
|
611
|
+
return schema
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
createHTTPScheme(securitySchema) {
|
|
615
|
+
const schema = {}
|
|
616
|
+
|
|
617
|
+
if (securitySchema.scheme)
|
|
618
|
+
schema.scheme = securitySchema.scheme
|
|
619
|
+
else
|
|
620
|
+
throw new Error('Security Scheme for "http" requires scheme')
|
|
621
|
+
|
|
622
|
+
if (securitySchema.bearerFormat)
|
|
623
|
+
schema.bearerFormat = securitySchema.bearerFormat
|
|
624
|
+
|
|
625
|
+
return schema
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
createOpenIDConnectScheme(securitySchema) {
|
|
629
|
+
const schema = {}
|
|
630
|
+
if (securitySchema.openIdConnectUrl)
|
|
631
|
+
schema.openIdConnectUrl = securitySchema.openIdConnectUrl
|
|
632
|
+
else
|
|
633
|
+
throw new Error('Security Scheme for "openIdConnect" requires openIdConnectUrl')
|
|
634
|
+
|
|
635
|
+
return schema
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
createOAuth2Scheme(securitySchema) {
|
|
639
|
+
const schema = {}
|
|
640
|
+
if (securitySchema.flows) {
|
|
641
|
+
const flows = this.createOAuthFlows(securitySchema.flows)
|
|
642
|
+
Object.assign(schema, {flows: flows})
|
|
643
|
+
} else
|
|
644
|
+
throw new Error('Security Scheme for "oauth2" requires flows')
|
|
645
|
+
|
|
646
|
+
return schema
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
createOAuthFlows(flows) {
|
|
650
|
+
const obj = {}
|
|
651
|
+
for (const flow of Object.keys(flows)) {
|
|
652
|
+
const schema = {}
|
|
653
|
+
if (["implicit", 'authorizationCode'].includes(flow))
|
|
654
|
+
if (flows[flow].authorizationUrl)
|
|
655
|
+
schema.authorizationUrl = flows[flow].authorizationUrl
|
|
656
|
+
else
|
|
657
|
+
throw new Error(`oAuth2 ${flow} flow requires an authorizationUrl`)
|
|
658
|
+
|
|
659
|
+
if (['password', 'clientCredentials', 'authorizationCode'].includes(flow)) {
|
|
660
|
+
if (flows[flow].tokenUrl)
|
|
661
|
+
schema.tokenUrl = flows[flow].tokenUrl
|
|
662
|
+
else
|
|
663
|
+
throw new Error(`oAuth2 ${flow} flow requires a tokenUrl`)
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (flows[flow].refreshUrl)
|
|
667
|
+
schema.refreshUrl = flows[flow].refreshUrl
|
|
668
|
+
|
|
669
|
+
if (flows[flow].scopes)
|
|
670
|
+
schema.scopes = flows[flow].scopes
|
|
671
|
+
else
|
|
672
|
+
throw new Error(`oAuth2 ${flow} flow requires scopes`)
|
|
673
|
+
|
|
674
|
+
Object.assign(obj, {[flow]: schema})
|
|
675
|
+
}
|
|
676
|
+
return obj
|
|
677
|
+
}
|
|
678
|
+
|
|
495
679
|
createExamples(examples) {
|
|
496
680
|
const examplesObj = {}
|
|
497
681
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const fs = require('fs').promises
|
|
4
4
|
const path = require('path')
|
|
5
5
|
const sinon = require('sinon')
|
|
6
|
-
const $RefParser = require("@apidevtools/json-schema-ref-parser")
|
|
6
|
+
const $RefParser = require("@apidevtools/json-schema-ref-parser")
|
|
7
7
|
const expect = require('chai').expect
|
|
8
8
|
|
|
9
9
|
const serverlessMock = require('../helpers/serverless')
|
|
@@ -174,6 +174,482 @@ describe('DefinitionGenerator', () => {
|
|
|
174
174
|
expect(definitionGenerator.openAPI.info).to.be.an('object')
|
|
175
175
|
expect(v4.test(definitionGenerator.openAPI.info.version)).to.be.true
|
|
176
176
|
});
|
|
177
|
+
|
|
178
|
+
it('should assign a contact Object when a contact object is included', function() {
|
|
179
|
+
mockServerless.service.custom.documentation.contact = {
|
|
180
|
+
name: 'John',
|
|
181
|
+
url: 'http://example.com',
|
|
182
|
+
email: 'john@example.com'
|
|
183
|
+
}
|
|
184
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
185
|
+
definitionGenerator.createInfo()
|
|
186
|
+
|
|
187
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
188
|
+
expect(definitionGenerator.openAPI.info).to.be.an('object')
|
|
189
|
+
expect(definitionGenerator.openAPI.info).to.have.property('contact')
|
|
190
|
+
expect(definitionGenerator.openAPI.info.contact).to.be.an('object')
|
|
191
|
+
expect(definitionGenerator.openAPI.info.contact.name).to.be.an('string')
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should only assign a contact url if one is provided', function() {
|
|
195
|
+
mockServerless.service.custom.documentation.contact = {
|
|
196
|
+
name: 'John',
|
|
197
|
+
email: 'john@example.com'
|
|
198
|
+
}
|
|
199
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
200
|
+
definitionGenerator.createInfo()
|
|
201
|
+
|
|
202
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
203
|
+
expect(definitionGenerator.openAPI.info).to.be.an('object')
|
|
204
|
+
expect(definitionGenerator.openAPI.info).to.have.property('contact')
|
|
205
|
+
expect(definitionGenerator.openAPI.info.contact).to.be.an('object')
|
|
206
|
+
expect(definitionGenerator.openAPI.info.contact.name).to.be.an('string')
|
|
207
|
+
expect(definitionGenerator.openAPI.info.contact).to.not.have.property('url')
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should assign a license Object when a license object is included with a name', function() {
|
|
211
|
+
mockServerless.service.custom.documentation.license = {
|
|
212
|
+
name: 'Apache 2.0',
|
|
213
|
+
url: 'https://www.apache.org/licenses/LICENSE-2.0.html',
|
|
214
|
+
}
|
|
215
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
216
|
+
definitionGenerator.createInfo()
|
|
217
|
+
|
|
218
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
219
|
+
expect(definitionGenerator.openAPI.info).to.be.an('object')
|
|
220
|
+
expect(definitionGenerator.openAPI.info).to.have.property('license')
|
|
221
|
+
expect(definitionGenerator.openAPI.info.license).to.be.an('object')
|
|
222
|
+
expect(definitionGenerator.openAPI.info.license.name).to.be.an('string')
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should not assign a license Object when a license object is included without a name', function() {
|
|
226
|
+
mockServerless.service.custom.documentation.license = {
|
|
227
|
+
url: 'https://www.apache.org/licenses/LICENSE-2.0.html',
|
|
228
|
+
}
|
|
229
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
230
|
+
definitionGenerator.createInfo()
|
|
231
|
+
|
|
232
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
233
|
+
expect(definitionGenerator.openAPI.info).to.be.an('object')
|
|
234
|
+
expect(definitionGenerator.openAPI.info).to.not.have.property('license')
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should only assign a contact url if one is provided', function() {
|
|
238
|
+
mockServerless.service.custom.documentation.license = {
|
|
239
|
+
name: 'John',
|
|
240
|
+
}
|
|
241
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
242
|
+
definitionGenerator.createInfo()
|
|
243
|
+
|
|
244
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
245
|
+
expect(definitionGenerator.openAPI.info).to.be.an('object')
|
|
246
|
+
expect(definitionGenerator.openAPI.info).to.have.property('license')
|
|
247
|
+
expect(definitionGenerator.openAPI.info.license).to.be.an('object')
|
|
248
|
+
expect(definitionGenerator.openAPI.info.license.name).to.be.an('string')
|
|
249
|
+
expect(definitionGenerator.openAPI.info.license).to.not.have.property('url')
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('should assign specification extension fields when included', function() {
|
|
253
|
+
mockServerless.service.custom.documentation['x-field'] = 'john'
|
|
254
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
255
|
+
definitionGenerator.createInfo()
|
|
256
|
+
|
|
257
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
258
|
+
expect(definitionGenerator.openAPI.info).to.be.an('object')
|
|
259
|
+
expect(definitionGenerator.openAPI.info).to.have.property('x-field')
|
|
260
|
+
expect(definitionGenerator.openAPI.info['x-field']).to.be.equal('john')
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should ignore fields that do not conform to specifiction extension', function() {
|
|
264
|
+
mockServerless.service.custom.documentation.otherField = 'john'
|
|
265
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
266
|
+
definitionGenerator.createInfo()
|
|
267
|
+
|
|
268
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
269
|
+
expect(definitionGenerator.openAPI.info).to.be.an('object')
|
|
270
|
+
expect(definitionGenerator.openAPI.info).to.not.have.property('otherField')
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
describe('createSecuritySchemes', () => {
|
|
275
|
+
describe('API Keys', () => {
|
|
276
|
+
it('should add an API Key security scheme to components', function() {
|
|
277
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
278
|
+
'api_key': {
|
|
279
|
+
type: 'apiKey',
|
|
280
|
+
name: 'Authorization',
|
|
281
|
+
in: 'header'
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
286
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
287
|
+
|
|
288
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
289
|
+
expect(definitionGenerator.openAPI.components).to.be.an('object')
|
|
290
|
+
expect(definitionGenerator.openAPI.components).to.have.property('securitySchemes')
|
|
291
|
+
expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an('object')
|
|
292
|
+
expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('api_key')
|
|
293
|
+
expect(definitionGenerator.openAPI.components.securitySchemes.api_key).to.have.property('type')
|
|
294
|
+
expect(definitionGenerator.openAPI.components.securitySchemes.api_key.type).to.be.equal('apiKey')
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('should throw an error when name is missing from an API Key scheme', function() {
|
|
298
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
299
|
+
'api_key': {
|
|
300
|
+
type: 'apiKey',
|
|
301
|
+
in: 'header'
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
306
|
+
expect(() => {
|
|
307
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
308
|
+
}).to.throw('Security Scheme for "apiKey" requires the name of the header, query or cookie parameter to be used')
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('should throw an error when in is missing from an API Key scheme', function() {
|
|
312
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
313
|
+
'api_key': {
|
|
314
|
+
type: 'apiKey',
|
|
315
|
+
name: 'Authorization',
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
320
|
+
expect(() => {
|
|
321
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
322
|
+
}).to.throw('Security Scheme for "apiKey" requires the location of the API key: header, query or cookie parameter')
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
describe('HTTP', () => {
|
|
327
|
+
it('should add an HTTP security scheme to components', function() {
|
|
328
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
329
|
+
'http_key': {
|
|
330
|
+
type: 'http',
|
|
331
|
+
scheme: 'basic'
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
336
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
337
|
+
|
|
338
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
339
|
+
expect(definitionGenerator.openAPI.components).to.be.an('object')
|
|
340
|
+
expect(definitionGenerator.openAPI.components).to.have.property('securitySchemes')
|
|
341
|
+
expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an('object')
|
|
342
|
+
expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('http_key')
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('should throw an error when scheme is missing from an HTTP scheme', function() {
|
|
346
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
347
|
+
'http_key': {
|
|
348
|
+
type: 'http',
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
353
|
+
expect(() => {
|
|
354
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
355
|
+
}).to.throw('Security Scheme for "http" requires scheme')
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
describe('openIdConnect', () => {
|
|
360
|
+
it('should add an openIdConnect security scheme to components', function() {
|
|
361
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
362
|
+
'openIdConnect_key': {
|
|
363
|
+
type: 'openIdConnect',
|
|
364
|
+
openIdConnectUrl: 'http://example.com'
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
369
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
370
|
+
|
|
371
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
372
|
+
expect(definitionGenerator.openAPI.components).to.be.an('object')
|
|
373
|
+
expect(definitionGenerator.openAPI.components).to.have.property('securitySchemes')
|
|
374
|
+
expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an('object')
|
|
375
|
+
expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('openIdConnect_key')
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it('should throw an error when openIdConnectUrl is missing from an openIdConnect scheme', function() {
|
|
379
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
380
|
+
'openIdConnect_key': {
|
|
381
|
+
type: 'openIdConnect',
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
386
|
+
expect(() => {
|
|
387
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
388
|
+
}).to.throw('Security Scheme for "openIdConnect" requires openIdConnectUrl')
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
describe('oauth2', () => {
|
|
393
|
+
it('should add an oauth2 security scheme to components', function() {
|
|
394
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
395
|
+
'oAuth2_key': {
|
|
396
|
+
type: 'oauth2',
|
|
397
|
+
flows: {
|
|
398
|
+
implicit: {
|
|
399
|
+
authorizationUrl: 'http://example.org/api/oauth/dialog',
|
|
400
|
+
scopes: {
|
|
401
|
+
'write:pets': 'modify pets in your account',
|
|
402
|
+
'read:pets': 'read your pets'
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
410
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
411
|
+
|
|
412
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
413
|
+
expect(definitionGenerator.openAPI.components).to.be.an('object')
|
|
414
|
+
expect(definitionGenerator.openAPI.components).to.have.property('securitySchemes')
|
|
415
|
+
expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an('object')
|
|
416
|
+
expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('oAuth2_key')
|
|
417
|
+
expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key).to.be.an('object')
|
|
418
|
+
expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key).to.have.property('type')
|
|
419
|
+
expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key).to.have.property('flows')
|
|
420
|
+
expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key.flows).to.be.an('object')
|
|
421
|
+
expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key.flows).to.have.property('implicit')
|
|
422
|
+
expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key.flows.implicit).to.be.an('object')
|
|
423
|
+
expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key.flows.implicit).to.have.property('scopes')
|
|
424
|
+
expect(definitionGenerator.openAPI.components.securitySchemes.oAuth2_key.flows.implicit.scopes).to.be.an('object')
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it('should throw an error when flows is missing from an oauth2 scheme', function() {
|
|
428
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
429
|
+
'oAuth2_key': {
|
|
430
|
+
type: 'oauth2',
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
435
|
+
expect(() => {
|
|
436
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
437
|
+
}).to.throw('Security Scheme for "oauth2" requires flows')
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it('should throw an error when authorizationUrl is missing from an oauth2 implicit flow scheme', function() {
|
|
441
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
442
|
+
'oAuth2_key': {
|
|
443
|
+
type: 'oauth2',
|
|
444
|
+
flows: {
|
|
445
|
+
implicit: {
|
|
446
|
+
scopes: {
|
|
447
|
+
'write:pets': 'modify pets in your account',
|
|
448
|
+
'read:pets': 'read your pets'
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
456
|
+
expect(() => {
|
|
457
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
458
|
+
}).to.throw('oAuth2 implicit flow requires an authorizationUrl')
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
it('should throw an error when authorizationUrl is missing from an oauth2 authorizationCode flow scheme', function() {
|
|
462
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
463
|
+
'oAuth2_key': {
|
|
464
|
+
type: 'oauth2',
|
|
465
|
+
flows: {
|
|
466
|
+
authorizationCode: {
|
|
467
|
+
tokenUrl: 'http://example.com',
|
|
468
|
+
scopes: {
|
|
469
|
+
'write:pets': 'modify pets in your account',
|
|
470
|
+
'read:pets': 'read your pets'
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
478
|
+
expect(() => {
|
|
479
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
480
|
+
}).to.throw('oAuth2 authorizationCode flow requires an authorizationUrl')
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
it('should throw an error when tokenUrl is missing from an oauth2 authorizationCode flow scheme', function() {
|
|
484
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
485
|
+
'oAuth2_key': {
|
|
486
|
+
type: 'oauth2',
|
|
487
|
+
flows: {
|
|
488
|
+
authorizationCode: {
|
|
489
|
+
authorizationUrl: 'http://example.org/api/oauth/dialog',
|
|
490
|
+
scopes: {
|
|
491
|
+
'write:pets': 'modify pets in your account',
|
|
492
|
+
'read:pets': 'read your pets'
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
500
|
+
expect(() => {
|
|
501
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
502
|
+
}).to.throw('oAuth2 authorizationCode flow requires a tokenUrl')
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it('should throw an error when tokenUrl is missing from an oauth2 password flow scheme', function() {
|
|
506
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
507
|
+
'oAuth2_key': {
|
|
508
|
+
type: 'oauth2',
|
|
509
|
+
flows: {
|
|
510
|
+
password: {
|
|
511
|
+
scopes: {
|
|
512
|
+
'write:pets': 'modify pets in your account',
|
|
513
|
+
'read:pets': 'read your pets'
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
521
|
+
expect(() => {
|
|
522
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
523
|
+
}).to.throw('oAuth2 password flow requires a tokenUrl')
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('should throw an error when tokenUrl is missing from an oauth2 clientCredentials flow scheme', function() {
|
|
527
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
528
|
+
'oAuth2_key': {
|
|
529
|
+
type: 'oauth2',
|
|
530
|
+
flows: {
|
|
531
|
+
clientCredentials: {
|
|
532
|
+
scopes: {
|
|
533
|
+
'write:pets': 'modify pets in your account',
|
|
534
|
+
'read:pets': 'read your pets'
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
542
|
+
expect(() => {
|
|
543
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
544
|
+
}).to.throw('oAuth2 clientCredentials flow requires a tokenUrl')
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
it('should throw an error when scopes is missing from an oauth2 clientCredentials flow scheme', function() {
|
|
548
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
549
|
+
'oAuth2_key': {
|
|
550
|
+
type: 'oauth2',
|
|
551
|
+
flows: {
|
|
552
|
+
clientCredentials: {
|
|
553
|
+
tokenUrl: 'http://example.com',
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
560
|
+
expect(() => {
|
|
561
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
562
|
+
}).to.throw('oAuth2 clientCredentials flow requires scopes')
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
it('should throw an error when scopes is missing from an oauth2 authorizationCode flow scheme', function() {
|
|
566
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
567
|
+
'oAuth2_key': {
|
|
568
|
+
type: 'oauth2',
|
|
569
|
+
flows: {
|
|
570
|
+
authorizationCode: {
|
|
571
|
+
tokenUrl: 'http://example.com',
|
|
572
|
+
authorizationUrl: 'http://example.org/api/oauth/dialog',
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
579
|
+
expect(() => {
|
|
580
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
581
|
+
}).to.throw('oAuth2 authorizationCode flow requires scopes')
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
it('should throw an error when scopes is missing from an oauth2 password flow scheme', function() {
|
|
585
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
586
|
+
'oAuth2_key': {
|
|
587
|
+
type: 'oauth2',
|
|
588
|
+
flows: {
|
|
589
|
+
password: {
|
|
590
|
+
tokenUrl: 'http://example.com',
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
597
|
+
expect(() => {
|
|
598
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
599
|
+
}).to.throw('oAuth2 password flow requires scopes')
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
it('should throw an error when scopes is missing from an oauth2 implicit flow scheme', function() {
|
|
603
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
604
|
+
'oAuth2_key': {
|
|
605
|
+
type: 'oauth2',
|
|
606
|
+
flows: {
|
|
607
|
+
implicit: {
|
|
608
|
+
authorizationUrl: 'http://example.org/api/oauth/dialog',
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
615
|
+
expect(() => {
|
|
616
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
617
|
+
}).to.throw('oAuth2 implicit flow requires scopes')
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
describe('Multiple Schemes', () => {
|
|
622
|
+
it('should add an oauth2 and an apiKey security scheme to components', function() {
|
|
623
|
+
mockServerless.service.custom.documentation.securitySchemes = {
|
|
624
|
+
'oAuth2_key': {
|
|
625
|
+
type: 'oauth2',
|
|
626
|
+
flows: {
|
|
627
|
+
implicit: {
|
|
628
|
+
authorizationUrl: 'http://example.org/api/oauth/dialog',
|
|
629
|
+
scopes: {
|
|
630
|
+
'write:pets': 'modify pets in your account',
|
|
631
|
+
'read:pets': 'read your pets'
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
},
|
|
636
|
+
'api_key': {
|
|
637
|
+
type: 'apiKey',
|
|
638
|
+
name: 'Authorization',
|
|
639
|
+
in: 'header'
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const definitionGenerator = new DefinitionGenerator(mockServerless)
|
|
644
|
+
definitionGenerator.createSecuritySchemes(mockServerless.service.custom.documentation.securitySchemes)
|
|
645
|
+
expect(definitionGenerator.openAPI).to.be.an('object')
|
|
646
|
+
expect(definitionGenerator.openAPI.components).to.be.an('object')
|
|
647
|
+
expect(definitionGenerator.openAPI.components).to.have.property('securitySchemes')
|
|
648
|
+
expect(definitionGenerator.openAPI.components.securitySchemes).to.be.an('object')
|
|
649
|
+
expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('oAuth2_key')
|
|
650
|
+
expect(definitionGenerator.openAPI.components.securitySchemes).to.have.property('api_key')
|
|
651
|
+
});
|
|
652
|
+
});
|
|
177
653
|
});
|
|
178
654
|
|
|
179
655
|
describe('createTags', () => {
|