Skip to content

Commit e91baa8

Browse files
committed
docs: add README.md
- `README.md` explains the motivation and how to use this library.
1 parent f50793a commit e91baa8

File tree

1 file changed

+343
-0
lines changed

1 file changed

+343
-0
lines changed

README.md

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
# cdk-rest-api-with-spec
2+
3+
Describe an [Amazon API Gateway (API Gateway)](https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html) REST API and the [OpenAPI](https://spec.openapis.org/oas/latest.html) definition at once with `cdk-rest-api-with-spec`.
4+
5+
## For whom is this library?
6+
7+
This library could help you if you would like to write a REST API and the OpenAPI definition at once using the CDK building blocks.
8+
See [_Background_](#background) for more details.
9+
10+
## Prerequisites
11+
12+
You have to install [Node.js](https://nodejs.org/en/) v12 or later.
13+
I have developed this library with Node.js v16.x.
14+
15+
This library is implemented for the [AWS Cloud Development Kit (CDK)](https://docs.aws.amazon.com/cdk/v2/guide/home.html) **version 2** and does not work with the CDK version 1.
16+
17+
## How to install
18+
19+
Please add this repository to your dependencies.
20+
21+
```sh
22+
npm install https://github.com/codemonger-io/cdk-cors-utils.git#v0.1.0
23+
```
24+
25+
This library is supposed to be used in a CDK v2 project, so it does not include the following modules in the `dependencies` but does in the `peerDependencies`.
26+
- [`aws-cdk-lib`](https://www.npmjs.com/package/aws-cdk-lib)
27+
- [`constructs`](https://www.npmjs.com/package/constructs)
28+
29+
As long as you are working on a CDK v2 project, you should not have to separately install them.
30+
31+
## Getting started
32+
33+
Please use [`RestApiWithSpec.createRestApi`](./api-docs/markdown/cdk-rest-api-with-spec.restapiwithspec.createrestapi.md) instead of the constructor of [`aws_apigateway.RestApi`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.RestApi.html).
34+
It will return an object which augments [`aws_apigateway.RestApi`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.RestApi.html) with the features to describe the OpenAPI definition.
35+
36+
```ts
37+
const api = RestApiWithSpec.createRestApi(this, 'example-api', {
38+
description: 'Example of RestApiWithSpec',
39+
openApiInfo: {
40+
version: '0.0.1',
41+
},
42+
openApiOutputPath: 'openapi.json',
43+
// ... other options
44+
});
45+
```
46+
47+
Please refer to the [use cases](#use-cases) and the [API documentation](#api-documentation) for more details.
48+
You can also find a working example in the [`example`](./example) folder.
49+
50+
## Background
51+
52+
Recently, I have been urged to write the OpenAPI definition of my REST API on API Gateway.
53+
As far as I know, there are two options to have the OpenAPI definition of a REST API on API Gateway.
54+
1. [Export the OpenAPI definition from an existing REST API](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-export-api.html)
55+
2. [Create a REST API by importing the OpenAPI definition](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-import-api.html)
56+
57+
### 1. Exporting the OpenAPI definition
58+
59+
Without any additional documentation, the OpenAPI definition exported from API Gateway is poorly constrained and useless.
60+
I have to [add a separate documentation resource](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-documenting-api.html) to every component of a REST API.
61+
It would be nice if I could construct REST API components and document them at once.
62+
63+
### 2. Importing the OpenAPI definition
64+
65+
I am familiar with the CDK building blocks to describe a REST API on API Gateway.
66+
I used to write a REST API with a plain [CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html) template and got tired of a lot of repetition.
67+
CDK has relieved me of that pain.
68+
I think writing a plain OpenAPI definition could bring the pain back to me, though I have not tried.
69+
70+
### Third option
71+
72+
Thus, I want a third option that enables me to **write a REST API and the OpenAPI definition at once** using the CDK building blocks.
73+
I hope this library would be the solution.
74+
75+
## Difference between SpecRestApi
76+
77+
CDK provides a construct with a similar name [`aws_apigateway.SpecRestApi`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.SpecRestApi.html).
78+
The goal of [`aws_apigateway.SpecRestApi`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.SpecRestApi.html) is to create a REST API by importing an existing OpenAPI definition, whereas the goal of this library is, the opposite, to create an OpenAPI definition by constructing a REST API.
79+
80+
## Use cases
81+
82+
### Describing a method
83+
84+
You can specify `summary` and `description` properties to the third argument of the [`IResourceWithSpec.addMethod`](./api-docs/markdown/cdk-rest-api-with-spec.iresourcewithspec.addmethod.md) method.
85+
86+
```ts
87+
api.root.addMethod(
88+
'GET',
89+
new apigateway.MockIntegration({
90+
// ... integration settings
91+
}),
92+
{
93+
operationName: 'getRoot',
94+
summary: 'Get root', // NEW!
95+
description: 'Returns the root object', // NEW!
96+
methodResponses: [
97+
{
98+
statusCode: '200',
99+
description: 'successful operation',
100+
},
101+
],
102+
}
103+
);
104+
```
105+
106+
The `operationName`, `summary`, and `description` properties correspond to the `operationId`, `summary`, and `description` properties of the [Operation Object](https://spec.openapis.org/oas/latest.html#operation-object) in the OpenAPI definition respectively.
107+
108+
Elements in the `methodResponses` property can have the `description` property which corresponds to the `description` property of the [Response Object](https://spec.openapis.org/oas/latest.html#response-object) in the OpenAPI definition.
109+
110+
### Describing request parameters
111+
112+
You can describe request parameters in the [`requestParameterSchemas`](./api-docs/markdown/cdk-rest-api-with-spec.methodoptionswithspec.requestparameterschemas.md) property of the third argument of the [`IResourceWithSpec.addMethod`](./api-docs/markdown/cdk-rest-api-with-spec.iresourcewithspec.addmethod.md) method.
113+
114+
```ts
115+
findByStatus.addMethod(
116+
'GET',
117+
new apigateway.MockIntegration({
118+
// ... integration settings
119+
}),
120+
{
121+
operationName: 'findPetsByStatus',
122+
requestParameterSchemas: {
123+
'method.request.querystring.status': {
124+
description: 'Status values that need to be considered for filter',
125+
required: false,
126+
explode: true,
127+
schema: {
128+
type: 'string',
129+
enum: ['available', 'pending', 'sold'],
130+
default: 'available',
131+
},
132+
},
133+
},
134+
},
135+
);
136+
```
137+
138+
The [`requestParameterSchemas`](./api-docs/markdown/cdk-rest-api-with-spec.methodoptionswithspec.requestparameterschemas.md) is a collection of key-value pairs and takes the same key as the [`requestParameters`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.MethodOptions.html#requestparameters) property, but it maps a key to an object which represents a [Parameter Object](https://spec.openapis.org/oas/latest.html#parameter-object), except for the `name` and `in` properties, in the OpenAPI definition rather than a `boolean` value.
139+
The `name` and `in` properties of the [Parameter Object](https://spec.openapis.org/oas/latest.html#parameter-object) are inferred from the key.
140+
So the above [`requestParameterSchemas`](./api-docs/markdown/cdk-rest-api-with-spec.methodoptionswithspec.requestparameterschemas.md) will become the following [Parameter Object](https://spec.openapis.org/oas/latest.html#parameter-object),
141+
142+
```ts
143+
[
144+
{
145+
name: 'status',
146+
in: 'query',
147+
description: 'Status values that need to be considered for filter',
148+
required: false,
149+
explode: true,
150+
schema: {
151+
type: 'string',
152+
enum: ['available', 'pending', 'sold'],
153+
default: 'available',
154+
},
155+
},
156+
]
157+
```
158+
159+
If you specify the [`requestParameterSchemas`](./api-docs/markdown/cdk-rest-api-with-spec.methodoptionswithspec.requestparameterschemas.md) property, you do not have to specify the [`requestParameters`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.MethodOptions.html#requestparameters) property.
160+
The [`requestParameters`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.MethodOptions.html#requestparameters) property given to the underlying [`aws_apigateway.IResource.addMethod`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.IResource.html#addwbrmethodhttpmethod-target-options) will be generated from the [`requestParameterSchemas`](./api-docs/markdown/cdk-rest-api-with-spec.methodoptionswithspec.requestparameterschemas.md) property such that `requestParameters[key] = requestParameterSchemas[key].required`.
161+
162+
If you omit the [`requestParameterSchemas`](./api-docs/markdown/cdk-rest-api-with-spec.methodoptionswithspec.requestparameterschemas.md) property but specify the [`requestParameters`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.MethodOptions.html#requestparameters) property, minimal [Parameter Object](https://spec.openapis.org/oas/latest.html#parameter-object)s will be created from the [`requestParameters`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.MethodOptions.html#requestparameters) property.
163+
Suppose you specify the following object to the [`requestParameters`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.MethodOptions.html#requestparameters) property,
164+
165+
```ts
166+
{
167+
'method.request.querystring.status': false,
168+
}
169+
```
170+
171+
then you will get
172+
173+
```ts
174+
[
175+
{
176+
name: 'status',
177+
in: 'query',
178+
required: false,
179+
schema: {
180+
type: 'string',
181+
},
182+
},
183+
]
184+
```
185+
186+
If the [`requestParameters`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.MethodOptions.html#requestparameters) and [`requestParameterSchemas`](./api-docs/markdown/cdk-rest-api-with-spec.methodoptionswithspec.requestparameterschemas.md) properties are both specified, the [`requestParameterSchemas`](./api-docs/markdown/cdk-rest-api-with-spec.methodoptionswithspec.requestparameterschemas.md) property precedes.
187+
188+
### Defining a model (schema)
189+
190+
The [`IRestApiWithSpec.addModel`](./api-docs/markdown/cdk-rest-api-with-spec.irestapiwithspec.addmodel.md) method will add a [Schema Object](https://spec.openapis.org/oas/latest.html#schema-object) to the `schemas` property of the [Components Object](https://spec.openapis.org/oas/latest.html#components-object) in the OpenAPI definition.
191+
Here is an example,
192+
193+
```ts
194+
const petModel = api.addModel('PetModel', {
195+
description: 'A pet',
196+
contentType: 'application/json',
197+
schema: {
198+
schema: apigateway.JsonSchemaVersion.DRAFT4,
199+
title: 'pet',
200+
description: 'A pet',
201+
type: apigateway.JsonSchemaType.OBJECT,
202+
properties: {
203+
id: {
204+
description: 'ID of the pet',
205+
type: apigateway.JsonSchemaType.INTEGER,
206+
format: 'int64',
207+
example: 123,
208+
},
209+
name: {
210+
description: 'Name of the pet',
211+
type: apigateway.JsonSchemaType.STRING,
212+
example: 'Monaka',
213+
},
214+
},
215+
},
216+
});
217+
```
218+
219+
The `schema` property, [`JsonSchemaEx`](./api-docs/markdown/cdk-rest-api-with-spec.jsonschemaex.md), of the second argument of the [`IRestApiWithSpec.addModel`](./api-docs/markdown/cdk-rest-api-with-spec.irestapiwithspec.addmodel.md) method will be translated into an equivalent [Schema Object](https://spec.openapis.org/oas/latest.html#schema-object) in the OpenAPI definition.
220+
221+
The [`aws_apigateway.IModel`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.IModel.html) referenced in the `responseModels` property in the `methodResponses` property of the third argument of the [`IResourceWithSpec.addMethod`](./api-docs/markdown/cdk-rest-api-with-spec.iresourcewithspec.addmethod.md) method will be replaced with a reference to the schema corresponding to the [`aws_apigateway.IModel`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.IModel.html) in the OpenAPI definition.
222+
223+
The `methodResponses` property in the following example,
224+
225+
```ts
226+
petId.addMethod(
227+
'GET',
228+
new apigateway.MockIntegration({
229+
// ... integration settings
230+
}),
231+
{
232+
operationName: 'getPetById',
233+
methodResponses: [
234+
{
235+
statusCode: '200',
236+
description: 'successful operation',
237+
responseModels: {
238+
'application/json': petModel,
239+
},
240+
},
241+
],
242+
},
243+
);
244+
```
245+
246+
will become a [Responses Object](https://spec.openapis.org/oas/latest.html#responses-object) similar to the following in the OpenAPI definition.
247+
248+
```ts
249+
{
250+
'200': {
251+
description: 'successful operation',
252+
content: {
253+
'application/json': {
254+
schema: {
255+
'$ref': '#/components/schemas/exampleapiPetModel43E308F7'
256+
},
257+
},
258+
},
259+
},
260+
}
261+
```
262+
263+
The CloudFormation resource ID given to an [`aws_apigateway.IModel`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.IModel.html) is used to represent the reference path to the [`aws_apigateway.IModel`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.IModel.html).
264+
265+
[`JsonSchemaEx`](./api-docs/markdown/cdk-rest-api-with-spec.jsonschemaex.md) which extends [`aws_apigateway.JsonSchema`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.JsonSchema.html) has an additional property [`modelRef`](./api-docs/markdown/cdk-rest-api-with-spec.jsonschemaex.modelref.md).
266+
You can reference another [`aws_apigateway.IModel`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.IModel.html) by using the [`modelRef`](./api-docs/markdown/cdk-rest-api-with-spec.jsonschemaex.modelref.md) property.
267+
268+
```ts
269+
const petArrayModel = api.addModel('PetArrayModel', {
270+
description: 'An array of pets',
271+
contentType: 'application/json',
272+
schema: {
273+
schema: apigateway.JsonSchemaVersion.DRAFT4,
274+
title: 'petArray',
275+
description: 'An array of pets',
276+
type: apigateway.JsonSchemaType.ARRAY,
277+
items: {
278+
modelRef: petModel,
279+
},
280+
},
281+
});
282+
```
283+
284+
### Describing an Authorizer
285+
286+
You can augment an existing [aws_apigateway.IAuthorizer](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.IAuthorizer.html) with the properties for the OpenAPI definition with the [`augmentAuthorizer`](./api-docs/markdown/cdk-rest-api-with-spec.augmentauthorizer.md) function.
287+
288+
```ts
289+
const authorizer = augmentAuthorizer(
290+
new apigateway.TokenAuthorizer(
291+
this,
292+
'ExampleAuthorizer',
293+
{
294+
handler: new nodejs.NodejsFunction(this, 'authorizer', {
295+
description: 'Example authorizer',
296+
runtime: lambda.Runtime.NODEJS_16_X,
297+
}),
298+
},
299+
),
300+
{
301+
type: 'apiKey',
302+
in: 'header',
303+
name: 'Authorization',
304+
},
305+
);
306+
```
307+
308+
The second argument of the [`augmentAuthorizer`](./api-docs/markdown/cdk-rest-api-with-spec.augmentauthorizer.md) function is a [Security Scheme Object](https://spec.openapis.org/oas/latest.html#security-scheme-object) to describe the authorizer in the OpenAPI definition.
309+
310+
## API documentation
311+
312+
The latest API documentation is available on [`api-docs/markdown/index.md`](./api-docs/markdown/index.md).
313+
314+
## Development
315+
316+
### Resolving dependencies
317+
318+
```sh
319+
npm install
320+
```
321+
322+
### Building the library
323+
324+
```sh
325+
npm run build
326+
```
327+
328+
You will find the following files created or updated in the `dist` folder,
329+
- `index.js`
330+
- `index.js.map`
331+
- `index.d.ts`
332+
333+
The `dist` folder will be created if it does not exist.
334+
335+
You will also find the file [`api-docs/cdk-rest-api-with-spec.api.md`](./api-docs/cdk-rest-api-with-spec.api.md) updated if there are any changes in the API of this library.
336+
337+
### Generating the documentation
338+
339+
```sh
340+
npm run doc
341+
```
342+
343+
This will replace the contents of the [`api-docs/markdown`](./api-docs/markdown) folder.

0 commit comments

Comments
 (0)