English / 日本語
Describe an Amazon API Gateway (API Gateway) REST API and the OpenAPI definition at once with cdk-rest-api-with-spec
.
This library could help you if you would like to write a REST API and the OpenAPI definition at once using the AWS Cloud Development Kit (CDK) building blocks. See "Background" for more details.
You have to install Node.js v12 or later. I have developed this library with Node.js v16.x.
This library is implemented for the CDK version 2 (CDK v2) and does not work with the CDK version 1.
Please add this repository to your dependencies.
npm install https://github.com/codemonger-io/cdk-rest-api-with-spec.git#v0.2.3
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
.
As long as you are working on a CDK v2 project, you should not have to separately install them.
Please instantiate RestApiWithSpec
instead of aws_apigateway.RestApi
.
const api = new RestApiWithSpec(this, 'example-api', {
description: 'Example of RestApiWithSpec',
openApiInfo: {
version: '0.0.1',
},
openApiOutputPath: 'openapi.json',
// ... other options
});
After synthesizing the CDK stack, you will find a file openapi.json
containing the OpenAPI definition created.
Please refer to the sections "Use cases" and "API documentation" for more details.
You can also find a working example in the example
folder.
Recently, I have been urged to write the OpenAPI definition of my REST API on API Gateway. As far as I know, there are two options to have the OpenAPI definition of a REST API on API Gateway.
- Export the OpenAPI definition from an existing REST API
- Create a REST API by importing the OpenAPI definition
Without any additional documentation, the OpenAPI definition exported from API Gateway is poorly constrained and useless. I have to add a separate documentation resource to every component of a REST API. It would be nice if I could construct REST API components and document them at once.
I am familiar with the CDK building blocks to describe a REST API on API Gateway. I used to write a REST API with a plain CloudFormation template and got tired of a lot of repetition. CDK has relieved me of that pain. I think writing a plain OpenAPI definition could bring the pain back to me, though I have not tried.
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. And I hope this library would be the solution.
CDK provides a construct with a similar name aws_apigateway.SpecRestApi
.
The goal of aws_apigateway.SpecRestApi
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.
You can specify summary
and description
properties to the third argument of the IResourceWithSpec.addMethod
method.
api.root.addMethod(
'GET',
new apigateway.MockIntegration({
// ... integration settings
}),
{
operationName: 'getRoot',
summary: 'Get root', // NEW!
description: 'Returns the root object', // NEW!
methodResponses: [
{
statusCode: '200',
description: 'successful operation',
},
],
}
);
The operationName
, summary
, and description
properties correspond to the operationId
, summary
, and description
properties of the Operation Object in the OpenAPI definition respectively.
Elements in the methodResponses
property can have the description
property which corresponds to the description
property of the Response Object in the OpenAPI definition.
You can describe request parameters in the requestParameterSchemas
property of the third argument of the IResourceWithSpec.addMethod
method.
findByStatus.addMethod(
'GET',
new apigateway.MockIntegration({
// ... integration settings
}),
{
operationName: 'findPetsByStatus',
requestParameterSchemas: { // NEW!
'method.request.querystring.status': {
description: 'Status values that need to be considered for filter',
required: false,
explode: true,
schema: {
type: 'string',
enum: ['available', 'pending', 'sold'],
default: 'available',
},
},
},
},
);
The requestParameterSchemas
property is a collection of key-value pairs and takes the same key as the requestParameters
property, but it maps a key to an object which represents a Parameter Object, except for the name
and in
properties, in the OpenAPI definition rather than a boolean
value.
The name
and in
properties of the Parameter Object are derived from the key.
So the above requestParameterSchemas
will become the following Parameter Object,
[
{
name: 'status',
in: 'query',
description: 'Status values that need to be considered for filter',
required: false,
explode: true,
schema: {
type: 'string',
enum: ['available', 'pending', 'sold'],
default: 'available',
},
},
]
If you specify the requestParameterSchemas
property, you do not have to specify the requestParameters
property.
The requestParameters
property given to the underlying aws_apigateway.IResource.addMethod
will be generated from the requestParameterSchemas
property such that requestParameters[key] = requestParameterSchemas[key].required
.
If you omit the requestParameterSchemas
property but specify the requestParameters
property, minimal Parameter Objects will be created from the requestParameters
property.
Suppose you specify the following object to the requestParameters
property,
{
'method.request.querystring.status': false,
}
then you will get
[
{
name: 'status',
in: 'query',
required: false,
schema: {
type: 'string',
},
},
]
If the requestParameters
and requestParameterSchemas
properties are both specified, the requestParameterSchemas
property precedes.
The IRestApiWithSpec.addModel
method will add a Schema Object to the schemas
property of the Components Object in the OpenAPI definition.
Here is an example,
const petModel = api.addModel('PetModel', {
description: 'A pet',
contentType: 'application/json',
schema: {
schema: apigateway.JsonSchemaVersion.DRAFT4,
title: 'pet',
description: 'A pet',
type: apigateway.JsonSchemaType.OBJECT,
properties: {
id: {
description: 'ID of the pet',
type: apigateway.JsonSchemaType.INTEGER,
format: 'int64',
example: 123,
},
name: {
description: 'Name of the pet',
type: apigateway.JsonSchemaType.STRING,
example: 'Monaka',
},
},
},
});
The schema
property, JsonSchemaEx
, of the second argument of the IRestApiWithSpec.addModel
method will be translated into an equivalent Schema Object in the OpenAPI definition.
The aws_apigateway.IModel
referenced in the responseModels
property in the methodResponses
property of the third argument of the IResourceWithSpec.addMethod
method will be replaced with a reference to the schema corresponding to the aws_apigateway.IModel
in the OpenAPI definition.
The methodResponses
property in the following example,
petId.addMethod(
'GET',
new apigateway.MockIntegration({
// ... integration settings
}),
{
operationName: 'getPetById',
methodResponses: [
{
statusCode: '200',
description: 'successful operation',
responseModels: {
'application/json': petModel,
},
},
],
},
);
will become a Responses Object similar to the following in the OpenAPI definition.
{
'200': {
description: 'successful operation',
content: {
'application/json': {
schema: {
'$ref': '#/components/schemas/exampleapiPetModel43E308F7'
},
},
},
},
}
The CloudFormation resource ID given to an aws_apigateway.IModel
is used to represent the reference path to the aws_apigateway.IModel
.
JsonSchemaEx
which extends aws_apigateway.JsonSchema
has an additional property modelRef
.
You can reference another aws_apigateway.IModel
in a schema by using the modelRef
property.
The following is an example of referencing another aws_apigateway.IModel
to specify the type of array items,
const petArrayModel = api.addModel('PetArrayModel', {
description: 'An array of pets',
contentType: 'application/json',
schema: {
schema: apigateway.JsonSchemaVersion.DRAFT4,
title: 'petArray',
description: 'An array of pets',
type: apigateway.JsonSchemaType.ARRAY,
items: {
modelRef: petModel,
},
},
});
You can augment an existing aws_apigateway.IAuthorizer with the properties for the OpenAPI definition with the augmentAuthorizer
function.
const authorizer = augmentAuthorizer(
new apigateway.TokenAuthorizer(
this,
'ExampleAuthorizer',
{
handler: new nodejs.NodejsFunction(this, 'authorizer', {
description: 'Example authorizer',
runtime: lambda.Runtime.NODEJS_18_X,
}),
},
),
{
type: 'apiKey',
in: 'header',
name: 'Authorization',
},
);
The second argument of the augmentAuthorizer
function is a Security Scheme Object to describe the authorizer in the OpenAPI definition.
The latest API documentation is available on api-docs/markdown/index.md
.
npm install
npm run build
You will find the following files created or updated in the dist
folder,
index.js
index.js.map
index.d.ts
The dist
folder will be created if it does not exist.
You will also find the file api-docs/cdk-rest-api-with-spec.api.md
updated if there are any changes in the API of this library.
npm run doc
This will replace the contents of the api-docs/markdown
folder.