Configuration

With a design in place, we need to configure and install the CDK. The CDK Install and Configure page explains this in great detail, saving me the trouble! Working from a new directory called save-request , run

cdk init --language=typescript

to initialise the CDK.

Within bin/save-request.ts , we have the CDK app. Whenever we deploy our stack, the CDK will run this app to execute deployment. We have no need to make any modifications to this file.

The stack itself will live in lib/save-request-stack.ts , which so far consists of an empty SaveRequestStack .

Each AWS service has its own CDK package. Following our design, we require packages for API Gateway, Lambda, and DynamoDB. We’ll also require the AWS IAM package, which will allow us to grant the Lambda permission to write to DynamoDB. We’ll see this later in the CDK code.

Adding these libraries to the initial dependencies, we have the below package.json .

To install these packages, run npm i .

Implementation

Now we’re ready to implement the stack. Returning to lib/save-request-stack.ts , we’ll include all our stack code within the SaveRequestStack class.

Let’s begin with the DynamoDB request table. Importing the DynamoDB package from package.json , we begin by instantiating a dynamodb.Table . Similar to the other CDK constructors, dynamodb.Table takes three parameters:

a scope (often a reference to the stack itself with this keyword), a unique name, and a JSON blob of CDK properties, which varies between constructors.

For the request table, let’s provide unique name “request-table”. Keep in mind that this is the name of the CDK construct, not the name of the table itself! We provide the latter within our JSON blob of CDK properties, along with the partition key and billing mode from our design.

The Lambda constructor takes a similar form with unique name “request-handler”. Within the properties, we include a pointer to the Lambda code, which I’ve saved in ./request-handler/app.py . The code property specifies which file or files contain the code, whilst the handler property indicates which method serves as the main method amongst those files.

Within the code, we reference a DYNAMODB_TABLE environment variable for the DynamoDB table name. Using the environment property, we can populate this variable. Better still, with CDK, we can dynamically reference the tableName property from the table we just defined.

After referencing the REQUEST_TABLE environment variable, the code executes the DynamoDB PutItem operation to write to the table. Without an IAM policy explicitly granting Lambda permission to do this, the Lambda will fail each time the PutItem method is called. With a few lines of CDK, we grant the required permission, referencing the table’s unique Amazon Resource Name (ARN) with the tableArn property.

With both DynamoDB and Lambda set up, now we need to create an API Gateway to send requests to the Lambda. Starting with a new REST API LambdaRestApi , we add a “send” resource that serves as our endpoint. This endpoint will always receive one of three responses from the Lambda code: a Bad Request, an Internal Server Error, or an OK. We define each of these using the IntegrationResponse type.

We proceed to integrate this endpoint to Lambda using a LambdaIntegration , which includes all three possible responses within its properties. Finally, we add the POST method support to this integration.

That forms our full stack! A total of 60 lines of TypeScript, which is available to view in GitLab. This translates into 254 lines of YAML once it’s converted into a CloudFormation template — over four times the size of our CDK!

Usage

It’s time to build and deploy this app to AWS. First run npm run build , followed by cdk deploy . The CDK will alert you to any security-related changes in your deployment — make sure you’re happy with these changes before proceeding!