Let’s CDK: The Energy Drink Episodes
Tags: aws, cdk, tutorial, serverless
Published: 2023-11-06 10:12:00

Ever since I started my foray into the world of Serverless, I have mainly worked with [Serverless Framework](https://www.serverless.com/) for my day-to-day development tasks. Don’t get me wrong; I have no beef with Serverless Framework; it has served me well while using it.

However, it appears that there is a [not-so-new](https://aws.amazon.com/blogs/aws/aws-cloud-development-kit-cdk-typescript-and-python-are-now-generally-available/) kid on the block that has caught my attention. Enter AWS Cloud Development Kit (CDK).

This post is part of a series that will introduce you to AWS CDK and how it can be used to create an application. This series will introduce you to the core concepts of AWS CDK, how you can deploy to your AWS account, and how services like AWS Lambda Functions, DynamoDB, Step Functions and more can all be used when working with CDK.

## AWS CD...What?
Rather than writing my own description of what AWS CDK is, I will borrow from [AWS’ FAQ page](https://aws.amazon.com/cdk/faqs/) to explain:

> The AWS Cloud Development Kit (AWS CDK) is an open-source software development framework for defining cloud infrastructure as code with modern programming languages and deploying it through AWS CloudFormation.

So, what does that really mean? I look at CDK in a similar way to LEGO bricks and sets. AWS CDK provides us with a bunch of base plates and bricks that allow us to build our super cool space stations or, in this case, serverless infrastructure. CDK provides us with many really cool constructs to leverage to create things we all know and love, like API Gateway, Lambda Functions and much more. You can find the [documentation for CDK here](https://docs.aws.amazon.com/cdk/api/v2/). It is worth looking at, even if you only glance over it to see how much it provides.

**Constructs = Building blocks**

![LEGO® set T. rex Breakout — Source: LEGO.com](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/evz91vsjede7so9pozdd.png)

Although it’s a scary-sounding word, [constructs in CDK are the basic building blocks of an AWS CDK application](https://docs.aws.amazon.com/prescriptive-guidance/latest/best-practices-cdk-typescript-iac/constructs-best-practices.html). To continue with our LEGO likeness, let’s imagine that we have the awesome [T. rex Breakout](https://www.lego.com/en-gb/product/t-rex-breakout-76956) set in front of us. We open the box and notice that the fence in the background and the enclosure plinth are already built for us, saving us some time and meaning we’re not building everything from scratch. This is basically how we can look at Constructs in CDK.

> A CDK Construct is basically our pre-made T. Rex enclosure plinth

**Construct types**
Another scary-sounding idea, I know, but fear not! Constructs in CDK are split into three different types:

* L1 Constructs:

_Official definition_: An L1 construct is the exact resource CloudFormation defines. Using a Cfn prefix, these constructs are basic and must be manually configured.

_Our LEGO analogy explanation_: These are our individual LEGO bricks. They are very basic, small pieces that aren’t much on their own. But are the foundation for our set.

* L2 Constructs:

_Official definition_: An L2 construct has common boilerplate code and logic. They come with default configurations and commonly combine corresponding L1 constructs.

_Our LEGO analogy explanation_: Think back to that pre-made enclosure plinth. An L2 construct is a lot like that. It contains a bunch of L1 constructs (basic bricks) but has a default configuration to be the shape of the plinth.

* L3 Constructs:

_Official definition_: Also called a pattern, these are designed to help complete full tasks. They involve multiple kinds of resources and are much more specific and opinionated in their configuration than an L2 construct.

_Our LEGO analogy explanation_: Remember that enclosure plinth? This is where it’s specified that it’s for the T. Rex. The opinionated and specific configuration designates this plinth for the T. Rex enclosure. We can see the L1 in the bricks and the L2 in the plinth itself with the specific config of the L3 setting us up with that T. Rex specificity.

## Piecing it together

![Photo by Charles Snow on Unsplash](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzef5cv8wwih48tsocr5.jpeg)
So far, we’ve looked at constructs in AWS CDK. You might wonder, ‘Do these constructs just float around and somehow interact?’. The answer to that is no. Constructs in CDK typically sit within what is called a ‘Stack’.

> A stack is a unit of deployment and has resources defined within its scope, either directly or indirectly.

We can easily identify multiple stacks if we return to our beloved Jurassic Park T. Rex Lego set. We could see stacks for the T. Rex, the cars, the fence and greenery, the baseplate, etc. If we take the T. Rex, for example, we can see the stack being structured as follows:

```
import { Construct } from 'constructs';
import { Stack, StackProps } from 'aws-cdk-lib';
import { LogGroup } from 'aws-cdk-lib/aws-logs';
import { Bucket} from 'aws-cdk-lib/aws-s3';
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
import { EventBus } from 'aws-cdk-lib/aws-events';
import { StateMachine } from 'aws-cdk-lib/aws-stepfunctions';

export class TRexStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // Head = Lambda Function
    new NodejsFunction(this, 'HeadLambdaFunction');

    // Body = S3 Bucket
    new Bucket(this, 'BodyBucket');

    // Tail = Cloudwatch log group
    new LogGroup(this, 'TailLogs');

    // Arms = Eventbridge event bus
    new EventBus(this, 'ArmsEventBus');

    // Legs = Step Function
    new StateMachine(this, 'LegsStateMachine', {
      // the definition of our state machine with our tasks etc.
      definition
    });
  }
}
```

The code example above defines a ‘TRexStack’, which extends the base Stack construct. This encapsulates a bunch of other constructs that define things like a Lambda Function, S3 bucket, Log group, etc. So basically, a Stack can be thought of as:

> A stack of building blocks that together form a part of your application

**We need a box to put it all in**

Our CDK application needs a box or a ‘container’ as with our LEGO set. In the context of CDK, an App acts as a container for one or more stacks. Note: When I mention ‘container,’ I don’t mean a docker container or similar. It acts as a wrapper that [serves as each stack’s scope](https://docs.aws.amazon.com/cdk/v2/guide/apps.html). Having the App construct serve each stack the same scope makes it easy for different Stacks to refer to each other's resources. If we refer back to our T. Rex set, the App would be the box with all the pieces and the instruction manual contained inside it.

```
import { App, Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { TRexStack } from './stacks/TRexStack';
import { CarsStack } from './stacks/CarsStack';
import { FenceStack } from './stacks/FenceStack';
import { MiniFiguresStack } from './stacks/MiniFiguresStack';
import { BasePlateStack } from './stacks/BasePlateStack';

const app = new App();

export class TRexBreaksOutStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // T. Rex Stack
    new TRexStack(this, 't-rex-ID');

    // Cars Stack
    new CarsStack(this, 'cars-ID');

    // Fence Stack
    new FenceStack(this, 'fence-ID');

    // Mini Figures Stack
    const miniFiguresStack = new MiniFiguresStack(this, 'mini-figures-ID');
    const miniFiguresStackDrGrantPath = miniFiguresStack.versionedBasePath.addResource('dr-grant');
    // Base Plate Stack
    new BasePlateStack(this, 'base-plate-ID', {
      // We can pass resources from one stack to another!
      drGrantPath: miniFiguresStackDrGrantPath
    });
  }
}

new TRexBreaksOutStack(app);
```

In the code example above, you can see that we create a new app and then [define the construct where the app is used as the parent scope](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.App.html). The code example above could be deployed to an AWS account, and the resources would be created. There are two main commands we need to be aware of when it comes to deployments:

1. `cdk synth` — This command executes your app, which causes the resources defined within it to be transformed into a CloudFormation template. A YAML-format template is
2. `cdk deploy` — As the name suggests, this command deploys the resources to your AWS account. This command will also synthesize your app before running the deployment to ensure that it is the latest version of your code that is being deployed.

## What’s this got to do with energy drinks?
I have waffled on at you for long enough about CDK, what it is, how we can deploy it, etc. But sometimes it’s more fun and easier to learn if we get our hands dirty and build something ourselves. So, I thought it would be fun if we took the application I mentioned in [my previous post here](https://medium.com/lego-engineering/energise-yourself-with-express-step-functions-6e01b8d86847) and built it using CDK.

I won't force you to read that previous post, although it would be awesome if you did! So here’s an outline of what the app is and needs to do:

**What it is:**
An application that helps the user choose which energy drink they should drink.

**What it needs to do:**
The application will need to be able to receive a POST request, run some logic based on that POST request and then return to the user information about the energy drink they should choose.

## Before we get started
I write code in TypeScript and will be running through this build using it. However, you can use any other language you like, provided AWS CDK supports it. If you are bored of me and want to run through a different tutorial on [getting started with CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html), AWS have a great one [here](https://docs.aws.amazon.com/cdk/v2/guide/hello_world.html).

If you are still here and willing to put up with me, there are some things you will need before you can start the build. These are:

- Node.js version 14.15.0 or later — You can find download links [here](https://nodejs.org/en/download).
- An installation of TypeScript — You can run `npm -g install typescript` to install it globally on your machine.
- Authentication with AWS — Instructions for this can be found [on this page](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html). This establishes how AWS CDK authenticates with the AWS services, allowing code deployment and other things.
- AWS CDK — You can run `npm install -g aws-cdk` to install it globally on your machine.

If you are using VS Code, the [AWS toolkit for VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/aws-cdk-apps.html) is helpful when working with CDK and AWS.

## Let’s get started!
We’ve gone through a lot so far in this post. Kudos to you for making it this far! So, for this first episode, we will run through the process of setting up the CDK app and deploying it to an AWS account.

First, let’s open up the terminal and either navigate to a directory you want to create the app in or create a new directory to create the app in. Let’s create a new directory and then jump into it by running the following in the terminal:

```
mkdir energy-drink-selector
cd energy-drink-selector
```

So now we’re in the `energy-drink-selector` directory, we can start setting up all the files and creating all the directories we need, right? Luckily, AWS has simplified the creation of a CDK app into a single command that we can run. This command is:

```
cdk init app --language typescript
```

Running this command in our `energy-drink-selector` directory will set up some files and folders to use as a base for creating the rest of our application. I recommend exploring what was generated and getting a feel for the code within it.

Let's add esbuild as a dependency, this will be needed in future episodes when running deployments. We can do this by running the following command in the project root:

```
npm i esbuild
```

As we now have a basic CDK application, we can deploy it to our AWS account. Let’s first synthesize the app by running:

```
cdk synth
```

This will create a YAML-format CloudFormation template and an output of our app in a `cdk.out` directory. We can then deploy our application to our AWS account using the command:

```
cdk deploy
```

You will see a progress bar as the stack within the application is deployed. Once the deployment has finished, you will be able to open your AWS console, navigate to CloudFormation, and you will be able to see the EnergyDrinkSelector stack.

## Aaaaand relax

![Photo by Clem Onojeghuo on Unsplash](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/37vyw4wrvk7nq1e74frf.jpeg)

With that, you have successfully created and deployed your first CDK app! We have run through quite a lot in this post, so let's have a quick recap before we call it a day and re-energise. We covered:

- What is CDK — Amazon Cloud Development Kit — An open-source framework for defining cloud infrastructure as code and deploying it through AWS CloudFormation
- Constructs and their types — A construct is a basic building block of a CDK application. They come in types including L1, L2 and L3. These types essentially describe how much boilerplate code there is and how opinionated the construct is.
- Stacks and the ‘App’ — A stack is a ‘unit of deployment’ which consists of one or many constructs, with the App being the parent ‘container’ that serves as the scope for each Stack.

Going forward, we will work with several AWS services such as API Gateway, DynamoDB, Step Functions and more! So stay tuned for the next episode, and go grab a much-deserved can of liquid energy! (or whichever type of beverage you prefer).