serverless-openapi-documenter 0.0.2 → 0.0.5
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.
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Create a report to help us improve
|
|
4
|
+
title: "[BUG]"
|
|
5
|
+
labels: ''
|
|
6
|
+
assignees: JaredCE
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
**Describe the bug**
|
|
11
|
+
A clear and concise description of what the bug is.
|
|
12
|
+
|
|
13
|
+
**To Reproduce**
|
|
14
|
+
Steps to reproduce the behavior:
|
|
15
|
+
```
|
|
16
|
+
serverless.yml
|
|
17
|
+
...
|
|
18
|
+
```
|
|
19
|
+
**Expected behavior**
|
|
20
|
+
A clear and concise description of what you expected to happen.
|
|
21
|
+
|
|
22
|
+
**Desktop (please complete the following information):**
|
|
23
|
+
- Serverless version: [e.g. 2.73.3]
|
|
24
|
+
- serverless-openapi-documenter version [e.g. 0.0.2]
|
|
25
|
+
|
|
26
|
+
**Additional context**
|
|
27
|
+
Add any other context about the problem here.
|
package/README.md
CHANGED
|
@@ -4,56 +4,87 @@ This will generate an OpenAPI V3 (up to v3.0.3) file for you from your serverles
|
|
|
4
4
|
|
|
5
5
|
Originally based off of: https://github.com/temando/serverless-openapi-documentation
|
|
6
6
|
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
This plugin works for Serverless 2.x and up.
|
|
10
|
+
|
|
11
|
+
To add this plugin to your package.json:
|
|
12
|
+
|
|
13
|
+
**Using npm:**
|
|
14
|
+
```bash
|
|
15
|
+
npm install --save-dev serverless-openapi-documenter
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Next you need to add the plugin to the `plugins` section of your `serverless.yml` file.
|
|
19
|
+
|
|
20
|
+
```yml
|
|
21
|
+
plugins:
|
|
22
|
+
- serverless-openapi-documenter
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
> Note: Add this plugin _after_ `serverless-offline` to prevent issues with `String.replaceAll` being overridden incorrectly.
|
|
26
|
+
|
|
7
27
|
## Adding documentation to serverless
|
|
8
28
|
|
|
9
29
|
To Run: `serverless openapi generate -o openapi.json -f json -a 3.0.3 -p postman.json`
|
|
10
30
|
|
|
11
31
|
Options:
|
|
12
32
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
33
|
+
```
|
|
34
|
+
--output -o What filename the OpenAPI documentation should output under. Default: openapi.json
|
|
35
|
+
--format -f Whether to output the OpenAPI documentation as json or yaml. Default: json
|
|
36
|
+
--indent -i File indentation in spaces. Default: 2
|
|
37
|
+
--openApiVersion -a OpenAPI version to generate for. Default: 3.0.0
|
|
38
|
+
--postmanCollection -p Will generate a postman collection (from the generated openAPI documentation), in json only, if passed in. Default postman.json
|
|
39
|
+
```
|
|
20
40
|
|
|
21
41
|
### OpenAPI Mapping
|
|
22
42
|
|
|
23
|
-
| OpenAPI field
|
|
24
|
-
|
|
25
|
-
| info.title
|
|
26
|
-
| info.description
|
|
27
|
-
| info.version
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
| path[path]
|
|
33
|
-
| path[path].
|
|
34
|
-
| path[path].
|
|
35
|
-
| path[path].[
|
|
36
|
-
| path[path].[
|
|
37
|
-
| path[path].[operation]
|
|
38
|
-
| path[path].[operation].
|
|
39
|
-
| path[path].[operation].
|
|
40
|
-
| path[path].[operation].
|
|
41
|
-
| path[path].[operation].
|
|
42
|
-
| path[path].[operation].
|
|
43
|
-
| path[path].[operation].
|
|
44
|
-
| path[path].[operation].
|
|
45
|
-
| path[path].[operation].
|
|
46
|
-
| path[path].[operation].
|
|
47
|
-
| path[path].[operation].parameters
|
|
48
|
-
| path[path].[operation].parameters.
|
|
49
|
-
| path[path].[operation].
|
|
50
|
-
| path[path].[operation].
|
|
51
|
-
| path[path].[operation].
|
|
52
|
-
| path[path].[operation].
|
|
53
|
-
| path[path].[operation].
|
|
54
|
-
| path[path].[operation].
|
|
55
|
-
| path[path].[operation].
|
|
56
|
-
| path[path].[operation].
|
|
43
|
+
| OpenAPI field | Serverless field |
|
|
44
|
+
|--------------------------|------------------------------------------------------------------------------------|
|
|
45
|
+
| info.title | custom.documentation.title OR service |
|
|
46
|
+
| info.description | custom.documentation.description OR blank string |
|
|
47
|
+
| info.version | custom.documentation.version OR random v4 uuid if not provided |
|
|
48
|
+
| externalDocs.description | custom.documentation.externalDocumentation.description |
|
|
49
|
+
| externalDocs.url | custom.documentation.externalDocumentation.url |
|
|
50
|
+
| servers[].description | custom.documentation.servers.description |
|
|
51
|
+
| servers[].url | custom.documentation.servers.url |
|
|
52
|
+
| path[path] | functions.functions.events.[http OR httpApi].path |
|
|
53
|
+
| path[path].summary | functions.functions.summary |
|
|
54
|
+
| path[path].description | functions.functions.description |
|
|
55
|
+
| path[path].servers[].description | functions.functions.servers.description |
|
|
56
|
+
| path[path].servers[].url | functions.functions.servers.url |
|
|
57
|
+
| path[path].[operation] | functions.functions.[http OR httpApi].method |
|
|
58
|
+
| path[path].[operation].summary | functions.functions.[http OR httpApi].documentation.summary |
|
|
59
|
+
| path[path].[operation].description | functions.functions.[http OR httpApi].documentation.description |
|
|
60
|
+
| path[path].[operation].operationId | functions.functions.[http OR httpApi].documentation.operationId OR functionName |
|
|
61
|
+
| path[path].[operation].deprecated | functions.functions.[http OR httpApi].documentation.deprecated |
|
|
62
|
+
| path[path].[operation].externalDocs.description | functions.functions.[http OR httpApi].documentation.externalDocumentation.description |
|
|
63
|
+
| path[path].[operation].externalDocs.url | functions.functions.[http OR httpApi].documentation.externalDocumentation.url |
|
|
64
|
+
| path[path].[operation].servers[].description | functions.functions.[http OR httpApi].documentation.servers.description |
|
|
65
|
+
| path[path].[operation].servers[].url | functions.functions.[http OR httpApi].documentation.servers.url |
|
|
66
|
+
| path[path].[operation].deprecated | functions.functions.[http OR httpApi].documentation.deprecated |
|
|
67
|
+
| path[path].[operation].parameters | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params |
|
|
68
|
+
| path[path].[operation].parameters.name | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params.name |
|
|
69
|
+
| path[path].[operation].parameters.in | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params |
|
|
70
|
+
| path[path].[operation].parameters.description | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params.description |
|
|
71
|
+
| path[path].[operation].parameters.required | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params.required |
|
|
72
|
+
| path[path].[operation].parameters.deprecated | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params.deprecated |
|
|
73
|
+
| path[path].[operation].parameters.allowEmptyValue | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params.allowEmptyValue |
|
|
74
|
+
| path[path].[operation].parameters.style | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params.style |
|
|
75
|
+
| path[path].[operation].parameters.explode | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params.explode |
|
|
76
|
+
| path[path].[operation].parameters.allowReserved | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params.allowReserved |
|
|
77
|
+
| path[path].[operation].parameters.schema | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params.schema |
|
|
78
|
+
| path[path].[operation].parameters.example | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params.example |
|
|
79
|
+
| path[path].[operation].parameters.examples | functions.functions.[http OR httpApi].documentation.[path|query|cookie|header]Params.examples |
|
|
80
|
+
| path[path].[operation].requestBody | functions.functions.[http OR httpApi].documentation.requestBody |
|
|
81
|
+
| path[path].[operation].requestBody.description | functions.functions.[http OR httpApi].documentation.requestBody.description |
|
|
82
|
+
| path[path].[operation].requestBody.required | functions.functions.[http OR httpApi].documentation.requestBody.required |
|
|
83
|
+
| path[path].[operation].requestBody.content | functions.functions.[http OR httpApi].documentation.requestModels[contentType].name Links to custom.documentation.models.name |
|
|
84
|
+
| path[path].[operation].responses | functions.functions.[http OR httpApi].documentation.methodResponses |
|
|
85
|
+
| path[path].[operation].requestBody.[statusCode] | functions.functions.[http OR httpApi].documentation.methodResponses[statusCode] |
|
|
86
|
+
| path[path].[operation].requestBody.[statusCode].description | functions.functions.[http OR httpApi].documentation.methodResponses[statusCode].responseBody.description |
|
|
87
|
+
| path[path].[operation].requestBody.[statusCode].content | functions.functions.[http OR httpApi].documentation.methodResponses[statusCode].responseModels[contentType] Links to custom.documentation.models.name |
|
|
57
88
|
|
|
58
89
|
|
|
59
90
|
### Configuration
|
|
@@ -69,6 +100,12 @@ custom:
|
|
|
69
100
|
title: 'My API'
|
|
70
101
|
description: 'This is my API'
|
|
71
102
|
models: {}
|
|
103
|
+
externalDocumentation:
|
|
104
|
+
url: https://google.com
|
|
105
|
+
description: A link to google
|
|
106
|
+
servers:
|
|
107
|
+
url: https://example.com
|
|
108
|
+
description: The server
|
|
72
109
|
```
|
|
73
110
|
|
|
74
111
|
These configurations can be quite verbose; you can separate it out into it's own file, such as `serverless.doc.yml` as below:
|
|
@@ -158,6 +195,9 @@ functions:
|
|
|
158
195
|
documentation:
|
|
159
196
|
summary: "Create User"
|
|
160
197
|
description: "Creates a user and then sends a generated password email"
|
|
198
|
+
externalDocumentation:
|
|
199
|
+
url: https://bing.com
|
|
200
|
+
description: A link to bing
|
|
161
201
|
requestBody:
|
|
162
202
|
description: "A user information object"
|
|
163
203
|
requestModels:
|
|
@@ -312,26 +352,6 @@ requestHeaders:
|
|
|
312
352
|
|
|
313
353
|
Please view the example [serverless.yml](test/serverless\ 2/serverless.yml).
|
|
314
354
|
|
|
315
|
-
## Install
|
|
316
|
-
|
|
317
|
-
This plugin works for Serverless 2.x and up.
|
|
318
|
-
|
|
319
|
-
To add this plugin to your package.json:
|
|
320
|
-
|
|
321
|
-
**Using npm:**
|
|
322
|
-
```bash
|
|
323
|
-
npm install serverless-openapi-documenter --save-dev
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
Next you need to add the plugin to the `plugins` section of your `serverless.yml` file.
|
|
327
|
-
|
|
328
|
-
```yml
|
|
329
|
-
plugins:
|
|
330
|
-
- serverless-openapi-documenter
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
> Note: Add this plugin _after_ `serverless-offline` to prevent issues with `String.replaceAll` being overridden incorrectly.
|
|
334
|
-
|
|
335
355
|
## License
|
|
336
356
|
|
|
337
357
|
MIT
|
package/package.json
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "serverless-openapi-documenter",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Generate OpenAPI v3 documentation and Postman Collections from your Serverless Config",
|
|
5
5
|
"main": "index.js",
|
|
6
|
-
"keywords": [
|
|
6
|
+
"keywords": [
|
|
7
|
+
"serverless",
|
|
8
|
+
"serverless2",
|
|
9
|
+
"serverless3",
|
|
10
|
+
"openAPI",
|
|
11
|
+
"openAPIv3",
|
|
12
|
+
"openAPI3",
|
|
13
|
+
"PostmanCollections",
|
|
14
|
+
"Postman-Collections"
|
|
15
|
+
],
|
|
7
16
|
"scripts": {
|
|
8
17
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
18
|
},
|
|
@@ -18,9 +27,6 @@
|
|
|
18
27
|
"url": "https://github.com/JaredCE/serverless-openapi-documenter/issues"
|
|
19
28
|
},
|
|
20
29
|
"license": "MIT",
|
|
21
|
-
"devDependencies": {
|
|
22
|
-
"serverless": "^3.17.0"
|
|
23
|
-
},
|
|
24
30
|
"dependencies": {
|
|
25
31
|
"chalk": "^4.1.2",
|
|
26
32
|
"js-yaml": "^4.1.0",
|
|
@@ -6,7 +6,7 @@ const SchemaConvertor = require('json-schema-for-openapi')
|
|
|
6
6
|
|
|
7
7
|
class DefinitionGenerator {
|
|
8
8
|
constructor(serverless, options = {}) {
|
|
9
|
-
this.version = options.
|
|
9
|
+
this.version = serverless.processedInput.options.openApiVersion || '3.0.0'
|
|
10
10
|
|
|
11
11
|
this.serverless = serverless
|
|
12
12
|
this.httpKeys = {
|
|
@@ -22,11 +22,18 @@ class DefinitionGenerator {
|
|
|
22
22
|
this.openAPI = {
|
|
23
23
|
openapi: this.version,
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
this.operationIds = []
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
parse() {
|
|
28
30
|
this.createInfo()
|
|
29
31
|
this.createPaths()
|
|
32
|
+
if (this.serverless.service.custom.documentation.servers) {
|
|
33
|
+
const servers = this.createServers(this.serverless.service.custom.documentation.servers)
|
|
34
|
+
Object.assign(this.openAPI, {servers: servers})
|
|
35
|
+
}
|
|
36
|
+
this.createExternalDocumentation()
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
createInfo() {
|
|
@@ -34,7 +41,7 @@ class DefinitionGenerator {
|
|
|
34
41
|
const documentation = this.serverless.service.custom.documentation;
|
|
35
42
|
|
|
36
43
|
const info = {
|
|
37
|
-
title: service.service,
|
|
44
|
+
title: documentation?.title || service.service,
|
|
38
45
|
description: documentation?.description || '',
|
|
39
46
|
version: documentation?.version || uuid(),
|
|
40
47
|
}
|
|
@@ -50,20 +57,77 @@ class DefinitionGenerator {
|
|
|
50
57
|
if (event?.http?.documentation || event?.httpApi?.documentation) {
|
|
51
58
|
const documentation = event.http.documentation || event.httpApi.documentation
|
|
52
59
|
|
|
53
|
-
|
|
60
|
+
let opId
|
|
61
|
+
if (this.operationIds.includes(httpFunction.functionInfo.name) === false) {
|
|
62
|
+
opId = httpFunction.functionInfo.name
|
|
63
|
+
this.operationIds.push(opId)
|
|
64
|
+
} else {
|
|
65
|
+
opId = `${httpFunction.functionInfo.name}-${uuid()}`
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const path = this.createOperationObject(event.http.method || event.httpApi.method, documentation, opId)
|
|
54
69
|
if (httpFunction.functionInfo?.summary)
|
|
55
70
|
path.summary = httpFunction.functionInfo.summary
|
|
56
71
|
|
|
57
72
|
if (httpFunction.functionInfo?.description)
|
|
58
73
|
path.description = httpFunction.functionInfo.description
|
|
59
74
|
|
|
60
|
-
|
|
75
|
+
if (httpFunction.functionInfo?.servers) {
|
|
76
|
+
const servers = this.createServers(httpFunction.functionInfo.servers)
|
|
77
|
+
path.servers = servers
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let slashPath = event.http.path
|
|
81
|
+
const pathStart = new RegExp(/^\//, 'g')
|
|
82
|
+
if (pathStart.test(slashPath) === false) {
|
|
83
|
+
slashPath = `/${event.http.path}`
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
Object.assign(paths, {[slashPath]: path})
|
|
61
87
|
}
|
|
62
88
|
}
|
|
63
89
|
}
|
|
64
90
|
Object.assign(this.openAPI, {paths})
|
|
65
91
|
}
|
|
66
92
|
|
|
93
|
+
createServers(servers) {
|
|
94
|
+
const serverDoc = servers
|
|
95
|
+
const newServers = []
|
|
96
|
+
|
|
97
|
+
if (Array.isArray(serverDoc)) {
|
|
98
|
+
for (const server of serverDoc) {
|
|
99
|
+
const obj = {
|
|
100
|
+
url: server.url,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (server.description) {
|
|
104
|
+
obj.description = server.description
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
newServers.push(obj)
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
const obj = {
|
|
111
|
+
url: servers.url,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (servers.description) {
|
|
115
|
+
obj.description = servers.description
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
newServers.push(obj)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return newServers
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
createExternalDocumentation() {
|
|
125
|
+
const documentation = this.serverless.service.custom.documentation
|
|
126
|
+
if (documentation.externalDocumentation) {
|
|
127
|
+
Object.assign(this.openAPI, {externalDocs: {...documentation.externalDocumentation}})
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
67
131
|
createOperationObject(method, documentation, name = uuid()) {
|
|
68
132
|
const obj = {
|
|
69
133
|
summary: documentation.summary || '',
|
|
@@ -93,8 +157,12 @@ class DefinitionGenerator {
|
|
|
93
157
|
obj.parameters = obj.parameters.concat(paramObject)
|
|
94
158
|
}
|
|
95
159
|
|
|
160
|
+
if (documentation.externalDocumentation) {
|
|
161
|
+
obj.externalDocs = documentation.externalDocumentation
|
|
162
|
+
}
|
|
163
|
+
|
|
96
164
|
if (Object.keys(documentation).includes('deprecated'))
|
|
97
|
-
obj
|
|
165
|
+
obj.deprecated = documentation.deprecated
|
|
98
166
|
|
|
99
167
|
if (documentation.requestBody)
|
|
100
168
|
obj.requestBody = this.createRequestBody(documentation)
|
|
@@ -102,6 +170,11 @@ class DefinitionGenerator {
|
|
|
102
170
|
if (documentation.methodResponses)
|
|
103
171
|
obj.responses = this.createResponses(documentation)
|
|
104
172
|
|
|
173
|
+
if (documentation.servers) {
|
|
174
|
+
const servers = this.createServers(documentation.servers)
|
|
175
|
+
obj.servers = servers
|
|
176
|
+
}
|
|
177
|
+
|
|
105
178
|
return {[method]: obj}
|
|
106
179
|
}
|
|
107
180
|
|
package/src/openAPIGenerator.js
CHANGED
|
@@ -70,7 +70,8 @@ class OpenAPIGenerator {
|
|
|
70
70
|
this.serverless.configSchemaHandler.defineFunctionProperties('aws', {
|
|
71
71
|
properties: {
|
|
72
72
|
// description: {type: 'string'},
|
|
73
|
-
summary: {type: 'string'}
|
|
73
|
+
summary: {type: 'string'},
|
|
74
|
+
servers: {type: ['object', 'array']},
|
|
74
75
|
}
|
|
75
76
|
})
|
|
76
77
|
}
|
|
@@ -126,7 +127,7 @@ class OpenAPIGenerator {
|
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
const postmanCollection = PostmanGenerator.convert(
|
|
129
|
-
{type: 'json', data: generator.openAPI},
|
|
130
|
+
{type: 'json', data: JSON.parse(JSON.stringify(generator.openAPI))},
|
|
130
131
|
{},
|
|
131
132
|
postmanGeneration
|
|
132
133
|
)
|
|
@@ -19,6 +19,9 @@ functions:
|
|
|
19
19
|
documentation:
|
|
20
20
|
summary: Create User
|
|
21
21
|
description: Creates a user and then sends a generated password email
|
|
22
|
+
externalDocumentation:
|
|
23
|
+
url: https://bing.com
|
|
24
|
+
description: A link to bing
|
|
22
25
|
requestBody:
|
|
23
26
|
description: A user information object
|
|
24
27
|
requestModels:
|
|
@@ -64,6 +67,9 @@ custom:
|
|
|
64
67
|
documentation:
|
|
65
68
|
description: This is a description of what this does
|
|
66
69
|
version: 1.0.0
|
|
70
|
+
externalDocumentation:
|
|
71
|
+
url: https://google.com
|
|
72
|
+
description: A link to google
|
|
67
73
|
models:
|
|
68
74
|
- name: ErrorResponse
|
|
69
75
|
description: This is an error
|