Skip to content

Describe a REST API and the OpenAPI definition side by side with CDK

License

Notifications You must be signed in to change notification settings

codemonger-io/cdk-rest-api-with-spec

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

87 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

English / 日本語

cdk-rest-api-with-spec

Describe an Amazon API Gateway (API Gateway) REST API and the OpenAPI definition at once with cdk-rest-api-with-spec.

For whom is this library?

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.

Prerequisites

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.

How to install

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.

Getting started

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.

Background

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.

  1. Export the OpenAPI definition from an existing REST API
  2. Create a REST API by importing the OpenAPI definition

1. Exporting 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.

2. Importing the OpenAPI definition

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.

Third option

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.

Difference between SpecRestApi

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.

Use cases

Describing a method

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.

Describing request parameters

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.

Defining a model (schema)

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,
    },
  },
});

Describing an Authorizer

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.

API documentation

The latest API documentation is available on api-docs/markdown/index.md.

Development

Resolving dependencies

npm install

Building the library

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.

Generating the documentation

npm run doc

This will replace the contents of the api-docs/markdown folder.

About

Describe a REST API and the OpenAPI definition side by side with CDK

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published