Skip to content

Commit 43ce6b6

Browse files
author
Abilio Henrique
committed
Updates
- Add missing `requestBody` and `responseBody` directives - Clean schemas for params and request/response headers - Add missing response headers - WIP: README.md - Add demo serverless.yml
1 parent 2d37787 commit 43ce6b6

File tree

5 files changed

+483
-22
lines changed

5 files changed

+483
-22
lines changed

README.md

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
# Serverless OpenAPI v3 Documentation Plugin
2+
3+
This plugin generates OpenAPI v3 documentation from serverless configuration files. OpenAPI is formerly known as Swagger. The configuration is extends the format specified by [serverless-aws-documentation](https://www.npmjs.com/package/serverless-aws-documentation).
4+
5+
6+
## Install
7+
8+
This plugin works for Serverless 1.x and up. Serverless 0.5 is not supported.
9+
10+
To add this plugin to your package.json:
11+
12+
**Using npm:**
13+
```bash
14+
npm install serverless-openapi-documentation --save-dev
15+
```
16+
17+
**Using Yarn:**
18+
```bash
19+
yarn add serverless-openapi-documentation --dev
20+
```
21+
22+
Next you need to add the plugin to the `plugins` section of your `serverless.yml` file.
23+
24+
```yml
25+
plugins:
26+
- serverless-openapi-documentation
27+
```
28+
29+
You can confirm the plugin is correctly installed by running:
30+
31+
```bash
32+
serverless | grep "ServerlessOpenAPIDocumentation"
33+
```
34+
35+
It should return `ServerlessOpenAPIDocumentation` as one of the plugins on the list.
36+
37+
## Usage
38+
39+
This plugin requires additional configuration to use, see the "[Configuration](#configuration)" section for how to configure the plugin to generate documentation.
40+
41+
Below are the commandline options to run the generator:
42+
43+
```bash
44+
serverless openapi generate [options]
45+
```
46+
### Options
47+
```bash
48+
Plugin: ServerlessOpenAPIDocumentation
49+
openapi generate ...................... Generate OpenAPI v3 Documentation
50+
--output / -o ...................... Output file location [default: openapi.yml|json]
51+
--format / -f ...................... OpenAPI file format (yml|json) [default: yml]
52+
--indent / -i ...................... File indentation in spaces[default: 2]
53+
--help / -h ...................... Help
54+
```
55+
56+
### Configuration
57+
58+
To configure this plugin to generate valid OpenAPI documentation there are two places you'll need to modify in your `serverless.yml` file, the `custom` variables section and the `http` event section for each given function in your service.
59+
60+
This plugin is compatible with the same documentation configuration as per [serverless-aws-documentation](https://www.npmjs.com/package/serverless-aws-documentation) and can run beside it.
61+
62+
The `custom` section of your `serverless.yml` can be configured as below:
63+
64+
```yml
65+
custom:
66+
documentation:
67+
version: '1'
68+
summary: 'My API'
69+
description: 'This is my API'
70+
```
71+
72+
If you find this configuration too verbose, you can separate it out into it's own file, such as `serverless.doc.yml` by replacing it with the following:
73+
74+
```yml
75+
custom:
76+
documentation: ${file(serverless.doc.yml):documentation}
77+
```
78+
79+
And instead putting the `documentation` section directly into `serverless.doc.yml`.
80+
81+
#### Defining models
82+
83+
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.
84+
85+
The *required* directives for the models section are as follow:
86+
87+
* `name`: the name of the schema
88+
* `description`: a description of the schema
89+
* `contentType`: the content type of the described request/response (ie. `application/json` or `application/xml`).
90+
* `schema`: The JSON Schema ([website](http://json-schema.org/)) that describes the model. You can either use inline `YAML` to define these, or refer to an external schema file as below
91+
92+
```yml
93+
custom:
94+
documentation:
95+
models:
96+
- name: "ErrorResponse"
97+
description: "This is an error"
98+
contentType: "application/json"
99+
schema: ${file(models/ErrorResponse.json)}
100+
- name: "PutDocumentResponse"
101+
description: "PUT Document response model (external reference example)"
102+
contentType: "application/json"
103+
schema: ${file(models/PutDocumentResponse.json)}
104+
- name: "PutDocumentRequest"
105+
description: "PUT Document request model (inline example)"
106+
contentType: "application/json"
107+
schema:
108+
$schema: "http://json-schema.org/draft-04/schema#"
109+
properties:
110+
SomeObject:
111+
type: "object"
112+
properties:
113+
SomeAttribute:
114+
type: "string"
115+
```
116+
117+
### Function event specific documentation
118+
119+
To define the documentation for a given function event, you need to create a `documentation` attribute for your http event in your `serverless.yml` file.
120+
121+
The `documentation` section of the event configuration can contain the following attributes:
122+
123+
* `summary`: a short description of the method
124+
* `description`: a detailed description of the method
125+
* `requestBody`: contains description of the request
126+
* `description`: a description of the request body
127+
* `requestModels`: a list of models to describe the request bodies (see [requestModels](#requestModels) below)
128+
* `queryParams`: a list of query parameters (see [queryParams](#queryParams) below)
129+
* `pathParams`: a list of path parameters (see [pathParams](#pathParams) below)
130+
* `cookieParams`: a list of cookie parameters (see [cookieParams](#cookieParams) below)
131+
* `methodResponses`: an array of response models and applicable status codes
132+
* `statusCode`: applicable http status code (ie. 200/404/500 etc.)
133+
* `responseBody`: contains description of the response
134+
* `description`: a description of the body response
135+
* `responseHeaders`: a list of response headers (see [responseHeaders](#responseHeaders) below)
136+
* `responseModels`: a list of models to describe the request bodies (see [responseModels](#responseModels) below) for each `Content-Type`
137+
138+
```yml
139+
functions:
140+
createUser:
141+
handler: "handler.create"
142+
events:
143+
- http:
144+
path: "create"
145+
method: "post"
146+
documentation:
147+
summary: "Create User"
148+
description: "Creates a user and then sends a generated password email"
149+
requestBody:
150+
description: "A user information object"
151+
requestModels:
152+
application/json: "PutDocumentRequest"
153+
pathParams:
154+
- name: "username"
155+
description: "The username for a user to create"
156+
schema:
157+
type: "string"
158+
pattern: "^[-a-z0-9_]+$"
159+
queryParams:
160+
- name: "membershipType"
161+
description: "The user's Membership Type"
162+
schema:
163+
type: "string"
164+
enum:
165+
- "premium"
166+
- "standard"
167+
cookieParams:
168+
- name: "SessionId"
169+
description: "A Session ID variable"
170+
schema:
171+
type: "string"
172+
methodResponses:
173+
- statusCode: 201
174+
responseBody:
175+
description: "A user object along with generated API Keys"
176+
responseModels:
177+
application/json: "PutDocumentResponse"
178+
- statusCode: 500
179+
responseBody:
180+
description: "An error message when creating a new user"
181+
responseModels:
182+
application/json: "ErrorResponse"
183+
```
184+
185+
#### queryParams
186+
187+
Query parameters can be described as follow:
188+
189+
* `name`: the name of the query variable
190+
* `description`: a description of the query variable
191+
* `required`: whether the query parameter is mandatory (boolean)
192+
* `schema`: JSON schema (inline or file)
193+
194+
```yml
195+
queryParams:
196+
- name: "filter"
197+
description: "The filter parameter"
198+
required: true
199+
schema:
200+
type: "string"
201+
```
202+
203+
#### pathParams
204+
205+
Path parameters can be described as follow:
206+
207+
* `name`: the name of the query variable
208+
* `description`: a description of the query variable
209+
* `schema`: JSON schema (inline or file)
210+
211+
```yml
212+
pathParams:
213+
- name: "usernameId"
214+
description: "The usernameId parameter"
215+
schema:
216+
type: "string"
217+
```
218+
219+
#### cookieParams
220+
221+
Cookie parameters can be described as follow:
222+
223+
* `name`: the name of the query variable
224+
* `description`: a description of the query variable
225+
* `required`: whether the query parameter is mandatory (boolean)
226+
* `schema`: JSON schema (inline or file)
227+
228+
```yml
229+
cookieParams:
230+
- name: "sessionId"
231+
description: "The sessionId parameter"
232+
required: true
233+
schema:
234+
type: "string"
235+
```
236+
237+
#### requestModels
238+
239+
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](#definingmodels) section).
240+
241+
```yml
242+
requestModels:
243+
application/json: "CreateRequest"
244+
application/xml: "CreateRequestXML"
245+
```
246+
247+
#### methodResponses
248+
249+
You can define the response schemas by defining properties for your function event.
250+
251+
For an example of a `methodResponses` configuration for an event see below:
252+
253+
```yml
254+
methodResponse:
255+
- statusCode: 200
256+
responseHeaders:
257+
- name: "Content-Type"
258+
description: "Content Type header"
259+
schema:
260+
type: "string"
261+
responseModels:
262+
application/json: "CreateResponse"
263+
application/xml: "CreateResponseXML"
264+
```
265+
266+
##### responseModels
267+
268+
The `responseModels` property allows you to define models for the HTTP Response of the function event. You can define a different model for each different `Content-Type`. You can define a reference to the relevant response model named in the `models` section of your configuration (see [Defining Models](#definingmodels) section).
269+
270+
```yml
271+
responseModels:
272+
application/json: "CreateResponse"
273+
application/xml: "CreateResponseXML"
274+
```
275+
276+
##### responseHeaders
277+
278+
The `responseHeaders` section of the configuration allows you to define the HTTP response headers for the function event.
279+
280+
The attributes for a response header are as follow:
281+
282+
* `name`: the name of the HTTP Header
283+
* `description`: a description of the HTTP Header
284+
* `schema`: JSON schema (inline or file)
285+
286+
```yml
287+
responseHeaders:
288+
- name: "Content-Type"
289+
description: "Content Type header"
290+
schema:
291+
type: "string"
292+
```
293+
294+
## Example configuration
295+
296+
Please view the example [serverless.yml](test/serverless.yml).
297+
298+
## Contribution
299+
`Insert: information on contibution here`
300+
301+
## License
302+
303+
MIT

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@
2727
"ts-node": "^3.0.2",
2828
"tslint": "^5.1.0",
2929
"tslint-eslint-rules": "^4.0.0",
30+
"typedoc": "^0.5.10",
3031
"typescript": "^2.2.2"
3132
},
3233
"dependencies": {
3334
"@jdw/jst": "^1.0.0-beta.10",
3435
"@types/bluebird": "^3.5.2",
35-
"@types/chalk": "^0.4.31",
3636
"@types/fs-promise": "^1.0.1",
3737
"@types/js-yaml": "^3.5.29",
3838
"bluebird": "^3.5.0",

src/generate.ts

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export default class DocumentGenerator {
9797
}
9898
}
9999
}
100-
};
100+
}
101101

102102
/**
103103
* Cleans schema objects to make them OpenAPI compatible
@@ -173,7 +173,7 @@ export default class DocumentGenerator {
173173

174174
// console.log(parameter);
175175
if (parameter.schema) {
176-
parameterConfig.schema = parameter.schema;
176+
parameterConfig.schema = this.cleanSchema(parameter.schema);
177177
}
178178

179179
if (parameter.example) {
@@ -220,9 +220,17 @@ export default class DocumentGenerator {
220220
merge(reqModelConfig, { example: clone(requestModel.example) });
221221
}
222222

223-
merge(requestBodies, {
224-
[requestModelType]: reqModelConfig,
225-
});
223+
const reqBodyConfig: { content: object, description?: string } = {
224+
content: {
225+
[requestModelType]: reqModelConfig,
226+
},
227+
};
228+
229+
if (documentationConfig.requestBody && 'description' in documentationConfig.requestBody) {
230+
reqBodyConfig.description = documentationConfig.requestBody.description;
231+
}
232+
233+
merge(requestBodies, reqBodyConfig);
226234
}
227235
}
228236
}
@@ -238,11 +246,29 @@ export default class DocumentGenerator {
238246
const responses = {};
239247
if (documentationConfig.methodResponses) {
240248
for (const response of documentationConfig.methodResponses) {
249+
const methodResponseConfig: { description: any, content: object, headers?: object } = {
250+
description: (
251+
(response.responseBody && 'description' in response.responseBody)
252+
? response.responseBody.description
253+
: `Status ${response.statusCode} Response`
254+
),
255+
content: this.getResponseContent(response.responseModels),
256+
};
257+
258+
if (response.responseHeaders) {
259+
methodResponseConfig.headers = {};
260+
for (const header of response.responseHeaders) {
261+
methodResponseConfig.headers[header.name] = {
262+
description: header.description || `${header.name} header`,
263+
};
264+
if (header.schema) {
265+
methodResponseConfig.headers[header.name].schema = this.cleanSchema(header.schema);
266+
}
267+
}
268+
}
269+
241270
merge(responses, {
242-
[response.statusCode]: {
243-
description: response.description || `Status ${response.statusCode} Response`,
244-
content: this.getResponseContent(response.responseModels),
245-
},
271+
[response.statusCode]: methodResponseConfig,
246272
});
247273
}
248274
}

0 commit comments

Comments
 (0)