<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lee Priest</title>
    <description>The latest articles on DEV Community by Lee Priest (@theleepriest).</description>
    <link>https://dev.to/theleepriest</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1064932%2F5e0b918c-e455-4ce9-bd95-0b4545b7a97b.jpeg</url>
      <title>DEV Community: Lee Priest</title>
      <link>https://dev.to/theleepriest</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/theleepriest"/>
    <language>en</language>
    <item>
      <title>The Energy Drink Episodes 4: The Return Of The Lambda Functions</title>
      <dc:creator>Lee Priest</dc:creator>
      <pubDate>Tue, 19 Dec 2023 11:32:27 +0000</pubDate>
      <link>https://dev.to/aws-builders/the-energy-drink-episodes-4-the-return-of-the-lambda-functions-4o0m</link>
      <guid>https://dev.to/aws-builders/the-energy-drink-episodes-4-the-return-of-the-lambda-functions-4o0m</guid>
      <description>&lt;p&gt;This post is the fourth part of a ‘Let’s CDK’ series. You can catch up on &lt;a href="https://dev.to/aws-builders/lets-cdk-the-energy-drink-episodes-4a4f"&gt;part 1 here&lt;/a&gt;, &lt;a href="https://dev.to/aws-builders/the-energy-drink-episodes-2-the-rise-of-the-amazon-api-gateway-36ea"&gt;part 2 here&lt;/a&gt; and &lt;a href="https://dev.to/aws-builders/the-energy-drink-episodes-3-the-step-function-awakens-1kni"&gt;part 3 here&lt;/a&gt;. This post is part of a series that will introduce you to the AWS Cloud Development Kit (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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Previous Steps
&lt;/h2&gt;

&lt;p&gt;In the last episode, we learned about AWS Step Functions and how we can create them using CDK. We created our own custom L3 construct for an express workflow Step Function and then created the body definition chain. We linked it all together nicely in a stack and then integrated it with our main app stack. Feel free to have a read-through of the previous episode if you need any refresher before you continue on.&lt;/p&gt;

&lt;h2&gt;
  
  
  There’s nothing wrong with returning!
&lt;/h2&gt;

&lt;p&gt;Now that we’ve refreshed our memories of the last episode, you may be aware that there were a couple of things that we added as placeholders that we promised to return to. These ‘things’ were the Lambda Functions that we use to perform some logic on our payload in our Express Step Function flow.&lt;/p&gt;

&lt;p&gt;Let’s take a quick look at how we implemented these Lambda functions via CDK in the previous episode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sugarFreeLambdaFunction = new NodejsFunction(this, 'SugarFreeLambdaFunction', {
    entry: path.join(__dirname, '../src/functions/sugarFree/sugarFree.ts'),
    runtime: Runtime.NODEJS_18_X,
    architecture: Architecture.ARM_64,
    handler: 'sugarFree',
    bundling: {
        sourceMap: true,
        minify: true,
        tsconfig: path.join(__dirname, '../tsconfig.json'),
    },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We used the &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs.NodejsFunction.html"&gt;&lt;code&gt;NodejsFunction&lt;/code&gt; construct to build a Node.js Lambda function bundled using esbuild&lt;/a&gt;. However, if we look a little closer at the implementation, there are some things that we will likely keep the same between all our Lambda functions we end up using. Things like the &lt;code&gt;runtime&lt;/code&gt;, &lt;code&gt;architecture&lt;/code&gt; and &lt;code&gt;bundling&lt;/code&gt; probably won’t change. Could we come up with a way to implement something that would handle this for us?&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s Construct Something…
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xqRdh5f9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6o4et8orviih9adpbqpx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xqRdh5f9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6o4et8orviih9adpbqpx.png" alt="An AI generated image of people working on software at wooden desks" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Terrible pun aside, you probably guessed that we can create a custom L3 construct for our Lambda functions. In this custom construct we can set sensible defaults that we want all of our Lambda functions to use. We can also make use of a &lt;code&gt;props&lt;/code&gt; object so things like the &lt;code&gt;entry&lt;/code&gt;, &lt;code&gt;handler&lt;/code&gt; and &lt;code&gt;tsconfig&lt;/code&gt; can be dynamic.&lt;/p&gt;

&lt;p&gt;To get started with our custom Lambda function construct let’s create a &lt;code&gt;LambdaFunctions&lt;/code&gt; directory in our &lt;code&gt;constructs&lt;/code&gt; directory. Inside there, let’s now create a &lt;code&gt;TSLambdaFunction.ts&lt;/code&gt; file to house our &lt;code&gt;construct&lt;/code&gt; code. Your &lt;code&gt;constructs&lt;/code&gt; directory structure should look a little something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
│
└───constructs/
    │
    ├───APIGateway/
    │
    └───LambdaFunctions/
    │
    └───StepFunctions/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In our new &lt;code&gt;TSLambdaFunctions.ts&lt;/code&gt; file, let’s take a look at what we’ll need to be importing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Architecture, Runtime } from "aws-cdk-lib/aws-lambda";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully, you can see some familiar faces in the imports above. The trusty &lt;code&gt;Stack&lt;/code&gt; and &lt;code&gt;Construct&lt;/code&gt; imports have been used throughout the series. The &lt;code&gt;NodejsFunction&lt;/code&gt; import provides us with the construct we are going to use to create the actual Lambda function. You may be wondering why we don’t just use the &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.Function.html"&gt;&lt;code&gt;Function&lt;/code&gt; construct&lt;/a&gt; to create our Lambda functions.&lt;/p&gt;

&lt;p&gt;As we’re working on a Node.js application, the &lt;code&gt;NodejsFunction&lt;/code&gt; construct makes things a lot simpler for us by handling the code bundling. As we’re also working in Typescript, the construct makes things easier for us again by handling the compilation from Typescript to Javascript. In a nutshell, as we’re working in Typescript, using the &lt;code&gt;NodejsFunction&lt;/code&gt; construct saves us time and effort and helps us get up and running quicker.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Architecture&lt;/code&gt; and &lt;code&gt;Runtime&lt;/code&gt; imports allow us to specify, as you can probably guess, what architecture and runtime our Lambda function should use. Although these two imports aren’t completely necessary, as they are optional props for the &lt;code&gt;NodejsFunction&lt;/code&gt; construct, we can specify our own values to override the defaults.&lt;/p&gt;

&lt;p&gt;Next, let’s have a think about the props that we will want to be able to pass into our &lt;code&gt;TSLambdaFunction&lt;/code&gt; construct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type LambdaFunctionProps = {
    serviceName: string;
    stage: string;
    entryPath: string;
    handlerName?: string;
    tsConfigPath: string;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breaking down the type above, we can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;serviceName: A string we will use to create the logical ID for our Lambda function&lt;/li&gt;
&lt;li&gt;stage: A string we will use to create the logical ID for our Lambda function. This could also be used to handle deployment stage-specific needs if needed.&lt;/li&gt;
&lt;li&gt;entryPath: A string that represents the path to the Lambda function handler code&lt;/li&gt;
&lt;li&gt;handlerName: An optional string that represents that name of the exported function from the entry file&lt;/li&gt;
&lt;li&gt;tsConfigPath: A string that represents the path to the tsconfig file. We will pass this explicitly so the construct knows exactly where our tsconfig file is &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs.BundlingOptions.html"&gt;rather than it having to try to work it out itself&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we have our imports and our props decided. Let’s get cracking on actually creating the construct. We can make use of the skeleton we’re familiar with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class TSLambdaFunction extends Construct {
    public readonly tsLambdaFunction: NodejsFunction;

    constructor(scope: Stack, id: string, props: LambdaFunctionProps) {
        super(scope, id);

         // This is where the fun stuff will live!
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we have the skeleton for our &lt;code&gt;TSLambdaFunction&lt;/code&gt; that extends the &lt;code&gt;Construct&lt;/code&gt; class. We set a public readonly property called &lt;code&gt;tsLambdaFunction&lt;/code&gt; so we are able to access the Lambda function created inside this construct when used inside our stacks.&lt;/p&gt;

&lt;p&gt;It’s time to have some fun by adding some meat to the bones of our skeleton. This ‘meat’ looks a little something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const {
    serviceName,
    stage,
    entryPath,
    handlerName = 'handler',
    tsConfigPath
} = props;

this.tsLambdaFunction = new NodejsFunction(this, `${serviceName}-${id}-${stage}`, {
    entry: entryPath,
    runtime: Runtime.NODEJS_18_X,
    architecture: Architecture.ARM_64,
    handler: handlerName,
    bundling: {
        sourceMap: true,
        minify: true,
        tsconfig: tsConfigPath,
    },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code, we first destructure parameters from our props object and then use the &lt;code&gt;NodejsFunction&lt;/code&gt; construct to create a Lambda function. This Lambda function is then set as the value of the readonly property we created.&lt;/p&gt;

&lt;p&gt;For our architecture, we went with &lt;code&gt;Architecture.ARM_64&lt;/code&gt; for the benefits like cost efficiency, performance and energy efficiency over the default of &lt;code&gt;Architecture.X86_64&lt;/code&gt; that the &lt;code&gt;NodejsFunction&lt;/code&gt; runs with. We also went with &lt;code&gt;Runtime.NODEJS_18_X&lt;/code&gt; as opposed to the default of &lt;code&gt;Runtime.NODEJS_LATEST&lt;/code&gt; out of caution, as I’ve been burned by Node version issues in the past. But in reality, for our app, the default would have been fine.&lt;/p&gt;

&lt;p&gt;With the snippets above, we have everything we need to be able to successfully create Lambda functions. The above can also be easily extended to include things like log groups, deployment options, alarms and much more. If we combine the above snippets we get this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Architecture, Runtime } from "aws-cdk-lib/aws-lambda";

type LambdaFunctionProps = {
    serviceName: string;
    stage: string;
    entryPath: string;
    handlerName?: string;
    tsConfigPath: string;
}

export class TSLambdaFunction extends Construct {
    public readonly tsLambdaFunction: NodejsFunction;

    constructor(scope: Stack, id: string, props: LambdaFunctionProps) {
        super(scope, id);

        const {
            serviceName,
            stage,
            entryPath,
            handlerName = 'handler',
            tsConfigPath
        } = props;

        this.tsLambdaFunction = new NodejsFunction(this, `${serviceName}-${id}-${stage}`, {
            entry: entryPath,
            runtime: Runtime.NODEJS_18_X,
            architecture: Architecture.ARM_64,
            handler: handlerName,
            bundling: {
                sourceMap: true,
                minify: true,
                tsconfig: tsConfigPath,
            },
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Time to Handle Our Handlers
&lt;/h2&gt;

&lt;p&gt;With our custom Lambda function construct now constructed, we can turn our attention to the placeholder handlers we created in the previous episode. As a refresher, this is what we currently have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const sugar = async () =&amp;gt; {
    return {
        statusCode: 200,
        body: {
          message: "Hello, Sugar World!"
        },
    };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This extremely basic placeholder won't fulfil the mission we need it to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Decide which energy drink we should drink&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will stick to a basic approach in how we’re going to figure out which drink we’ll be given so we don’t get too far away from the mission of this post:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To learn how to create and deploy a Lambda function using CDK&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To contain everything to the Lambda handler, we can use a very basic implementation as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type sugarEvent = {
  sugar: boolean
}

export const sugar = async (event: sugarEvent) =&amp;gt; {
    const {sugar} = event;

    if(sugar) {
      return {
        drinkName: 'Relentless'
      }
    }

    throw new Error('Sugar boolean is false, should be true');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above snippet shows the Lambda function handler receives an event that contains a &lt;code&gt;sugar&lt;/code&gt; parameter that is a boolean. There is then a simple check in the code to detect if the &lt;code&gt;sugar&lt;/code&gt; boolean is true or not. If it is true we return the &lt;code&gt;drinkName&lt;/code&gt; of &lt;a href="https://www.relentlessenergy.com/"&gt;&lt;code&gt;Relentless&lt;/code&gt;&lt;/a&gt;. Otherwise, we throw an error. If you think back to our Step Function, we will have two separate handlers for the sugar and the sugar-free path. This means that if our &lt;code&gt;sugar&lt;/code&gt; Lambda Function receives a boolean that is false, something has gone wrong somewhere. For our &lt;code&gt;sugarFree&lt;/code&gt; Lambda Function we can use the same structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type sugarEvent = {
  sugar: boolean
}

export const sugarFree = async (event: sugarEvent) =&amp;gt; {
    const {sugar} = event;

    if(!sugar) {
      return {
        drinkName: 'Relentless Sugar Free'
      }
    }

    throw new Error('Sugar boolean is true, should be false');
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step Back to Our Definition
&lt;/h2&gt;

&lt;p&gt;Custom Lambda function construct, check. Updated Lambda handlers, check. We’re making good progress so far, so next up is updating our Step Function definition. Don’t be scared! There isn’t much we actually need to update. Let’s first have a refresher on what our current definition looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const definition = storeRawItem.addCatch(failState).next(
    validatePayload
        .when(Condition.isPresent('$.sugar'), isSugarFree
            .when(Condition.booleanEquals('$.sugar', true), new LambdaInvoke(stack, 'Sugar Logic', {
                lambdaFunction: sugarLambdaFunction,
            }).addCatch(sugarPassState, { errors: ['States.ALL'] }))
            .otherwise(new LambdaInvoke(stack, 'Sugar Free Logic', {
                lambdaFunction: sugarFreeLambdaFunction,
            }).addCatch(sugarFreePassState, { errors: ['States.ALL'] }))
        )
        .otherwise(failState)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at the above definition, we can see that the Lambda functions are being invoked depending on the presence of and the value of the &lt;code&gt;sugar&lt;/code&gt; parameter in the Step Function input. To work out what updates we need to make to the Step Function definition, let’s consider the updates made to our Lambda Function handlers.&lt;/p&gt;

&lt;p&gt;The handlers now return an object with a &lt;code&gt;drinkName&lt;/code&gt; parameter. This parameter contains the value of the drink we have been assigned. With this in mind, we should get that &lt;code&gt;drinkName&lt;/code&gt; parameter from the Lambda Function so we can return it to the user that triggered the Step Function. We can do this by updating the definition like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const definition = storeRawItem.addCatch(failState).next(
    validatePayload
        .when(Condition.isPresent('$.sugar'), isSugarFree
            .when(Condition.booleanEquals('$.sugar', true), new LambdaInvoke(stack, 'Sugar Logic', {
                lambdaFunction: sugarLambdaFunction,
                resultSelector: {
                    drinkName: JsonPath.stringAt('$.Payload.drinkName')
                }
            }).addCatch(sugarPassState, { errors: ['States.ALL'] }))
            .otherwise(new LambdaInvoke(stack, 'Sugar Free Logic', {
                lambdaFunction: sugarFreeLambdaFunction,
                resultSelector: {
                    drinkName: JsonPath.stringAt('$.Payload.drinkName')
                }
            }).addCatch(sugarFreePassState, { errors: ['States.ALL'] }))
        )
        .otherwise(failState)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the whole, the definition hasn’t changed much at all. The use of &lt;code&gt;resultSelector&lt;/code&gt; enables us to get the result from the Lambda Function and then set it as the Step Function data. So when we run the Step Function now, the result would be formatted like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "drinkName": "Relentless Sugar Free"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our needs, that’s all we need to update when considering the Step Function definition. Not so scary after all, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack Up Those Updates
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NDNW21T0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pib1fcmvhe7py8zce3lw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NDNW21T0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pib1fcmvhe7py8zce3lw.png" alt="An AI generated image of people coding around a central stack of blocks" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our Lambda Function construct is ready to go, the handler code has been updated and the Step Function definition is all good, so what next? Let’s take a look at our &lt;code&gt;EnergyDrinkSelectorStepFunctionStack&lt;/code&gt; and see what updates we may need there.&lt;/p&gt;

&lt;p&gt;The stack should currently look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import path = require("path");
import { Construct } from "constructs";
import { NestedStack, NestedStackProps } from "aws-cdk-lib";
import { StateMachine } from "aws-cdk-lib/aws-stepfunctions";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Architecture, Runtime } from "aws-cdk-lib/aws-lambda";
import { ITable } from "aws-cdk-lib/aws-dynamodb";
import { ExpressStepFunction } from "../constructs/StepFunctions/ExpressStepFunction";
import { energyDrinkSelectorDefinition } from "../src/stepFunctions/definitions/energyDrinkSelector";

type EnergyDrinkSelectorStepFunctionStackProps = NestedStackProps &amp;amp; {
    table: ITable;
}

export class EnergyDrinkSelectorStepFunctionStack extends NestedStack {
    public readonly stepFunction: StateMachine;

    constructor(scope: Construct, id: string, props: EnergyDrinkSelectorStepFunctionStackProps) {
        super(scope, id, props);

        const { table } = props;

        const sugarFreeLambdaFunction = new NodejsFunction(this, 'SugarFreeLambdaFunction', {
            entry: path.join(__dirname, '../src/functions/sugarFree/sugarFree.ts'),
            runtime: Runtime.NODEJS_18_X,
            architecture: Architecture.ARM_64,
            handler: 'sugarFree',
            bundling: {
                sourceMap: true,
                minify: true,
                tsconfig: path.join(__dirname, '../tsconfig.json'),
            },
        });

        const sugarLambdaFunction = new NodejsFunction(this, 'SugarLambdaFunction', {
            entry: path.join(__dirname, '../src/functions/sugar/sugar.ts'),
            runtime: Runtime.NODEJS_18_X,
            architecture: Architecture.ARM_64,
            handler: 'sugar',
            bundling: {
                sourceMap: true,
                minify: true,
                tsconfig: path.join(__dirname, '../tsconfig.json'),
            },
        });

        const energyDrinkSelectorStepFunction = new ExpressStepFunction(this, 'EnergyDrinkSelectorExpress', {
            serviceName: 'energy-drink-selector',
            stage: 'dev',
            definition: energyDrinkSelectorDefinition({
                stack: this,
                energyDrinkTable: table,
                sugarLambdaFunction: sugarLambdaFunction, 
                sugarFreeLambdaFunction: sugarFreeLambdaFunction
            }),
        });

        this.stepFunction = energyDrinkSelectorStepFunction.stateMachine;
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully, you can see a few places where we can make some updates to make use of our new &lt;code&gt;TSLambdaFunction&lt;/code&gt; construct and maybe a little housekeeping, too.&lt;/p&gt;

&lt;p&gt;The first thing we can do is take the &lt;code&gt;tsconfig&lt;/code&gt; path we’re creating and store that in a variable before we create our Lambda functions. Let’s add that underneath the destructuring of the &lt;code&gt;table&lt;/code&gt; parameter from the props object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const tsConfigPath = path.join(__dirname, '../tsconfig.json');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we can update how we’re creating the Lambda functions in the stack. We can use our shiny new L3 construct but we’ll first need to import it, let’s add the import at the top of the file with the rest of the imports and remove the &lt;code&gt;NodejsFunction&lt;/code&gt; import:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import path = require("path");
import { Construct } from "constructs";
import { NestedStack, NestedStackProps } from "aws-cdk-lib";
import { StateMachine } from "aws-cdk-lib/aws-stepfunctions";
import { ITable } from "aws-cdk-lib/aws-dynamodb";
import { ExpressStepFunction } from "../constructs/StepFunctions/ExpressStepFunction";
import { energyDrinkSelectorDefinition } from "../src/stepFunctions/definitions/energyDrinkSelector";
import { TSLambdaFunction } from "../constructs/LambdaFunction/TSLambdaFunction";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With our imports updated, we can now use the &lt;code&gt;TSLambdaFunction&lt;/code&gt; construct in place of the &lt;code&gt;NodejsFunction&lt;/code&gt; construct. We can go from this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sugarFreeLambdaFunction = new NodejsFunction(this, 'SugarFreeLambdaFunction', {
    entry: path.join(__dirname, '../src/functions/sugarFree/sugarFree.ts'),
    runtime: Runtime.NODEJS_18_X,
    architecture: Architecture.ARM_64,
    handler: 'sugarFree',
    bundling: {
        sourceMap: true,
        minify: true,
        tsconfig: path.join(__dirname, '../tsconfig.json'),
    },
});

const sugarLambdaFunction = new NodejsFunction(this, 'SugarLambdaFunction', {
    entry: path.join(__dirname, '../src/functions/sugar/sugar.ts'),
    runtime: Runtime.NODEJS_18_X,
    architecture: Architecture.ARM_64,
    handler: 'sugar',
    bundling: {
        sourceMap: true,
        minify: true,
        tsconfig: path.join(__dirname, '../tsconfig.json'),
    },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sugarFreeLambdaFunction = new TSLambdaFunction(this, 'SugarFreeLambdaFunction', {
    serviceName: 'energy-drink-selector',
    stage: 'dev',
    handlerName: 'sugarFree',
    entryPath: path.join(__dirname, '../src/functions/sugarFree/sugarFree.ts'),
    tsConfigPath
});

const sugarLambdaFunction =  new TSLambdaFunction(this, 'SugarLambdaFunction', {
    serviceName: 'energy-drink-selector',
    stage: 'dev',
    handlerName: 'sugar',
    entryPath: path.join(__dirname, '../src/functions/sugar/sugar.ts'),
    tsConfigPath
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks a bit neater and nicer, right? It remains somewhat familiar to the implementation of the &lt;code&gt;NodejsFunction&lt;/code&gt; construct but becomes a little easier to read and has our defaults for bundling and other parameters handled. With these updates our &lt;code&gt;EnergyDrinkSelectorStepFunctionStack&lt;/code&gt; should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import path = require("path");
import { Construct } from "constructs";
import { NestedStack, NestedStackProps } from "aws-cdk-lib";
import { StateMachine } from "aws-cdk-lib/aws-stepfunctions";
import { ITable } from "aws-cdk-lib/aws-dynamodb";
import { ExpressStepFunction } from "../constructs/StepFunctions/ExpressStepFunction";
import { energyDrinkSelectorDefinition } from "../src/stepFunctions/definitions/energyDrinkSelector";
import { TSLambdaFunction } from "../constructs/LambdaFunction/TSLambdaFunction";

type EnergyDrinkSelectorStepFunctionStackProps = NestedStackProps &amp;amp; {
    table: ITable;
}

export class EnergyDrinkSelectorStepFunctionStack extends NestedStack {
    public readonly stepFunction: StateMachine;

    constructor(scope: Construct, id: string, props: EnergyDrinkSelectorStepFunctionStackProps) {
        super(scope, id, props);

        const { table } = props;
        const tsConfigPath = path.join(__dirname, '../tsconfig.json');

        const sugarFreeLambdaFunction = new TSLambdaFunction(this, 'SugarFreeLambdaFunction', {
            serviceName: 'energy-drink-selector',
            stage: 'dev',
            handlerName: 'sugarFree',
            entryPath: path.join(__dirname, '../src/functions/sugarFree/sugarFree.ts'),
            tsConfigPath
        });

        const sugarLambdaFunction =  new TSLambdaFunction(this, 'SugarLambdaFunction', {
            serviceName: 'energy-drink-selector',
            stage: 'dev',
            handlerName: 'sugar',
            entryPath: path.join(__dirname, '../src/functions/sugar/sugar.ts'),
            tsConfigPath
        });

        const energyDrinkSelectorStepFunction = new ExpressStepFunction(this, 'EnergyDrinkSelectorExpress', {
            serviceName: 'energy-drink-selector',
            stage: 'dev',
            definition: energyDrinkSelectorDefinition({
                stack: this,
                energyDrinkTable: table,
                sugarLambdaFunction: sugarLambdaFunction.tsLambdaFunction, 
                sugarFreeLambdaFunction: sugarFreeLambdaFunction.tsLambdaFunction
            }),
        });

        this.stepFunction = energyDrinkSelectorStepFunction.stateMachine;
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Go Forth and Deploy!
&lt;/h2&gt;

&lt;p&gt;With those last updates, we now have everything in place to have the full working end-to-end flow! We should now have a fully working app that can fulfil the mission of suggesting what energy drink we should drink based on a sugar/sugar-free preference.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eKuU_f56--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9crcp420nv0j67oygpft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eKuU_f56--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9crcp420nv0j67oygpft.png" alt="A diagram showing an Express Step Function that handles the decision of sugar vs sugar free energy drink" width="800" height="558"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Aaaaand relax
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qDagpoNJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjaed4du0heisk0ijelh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qDagpoNJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjaed4du0heisk0ijelh.png" alt="An AI generated image showing people relaxing on beanbags and chairs" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this episode, we have covered quite a few things, with our main focus on how we can create Lambda functions in CDK.&lt;/p&gt;

&lt;p&gt;We created our own custom L3 construct that contains sensible defaults we want all our Lambda functions to use. Having this custom construct will also help with any updates we may make going forward. We would only have to update this construct rather than track down every use of the &lt;code&gt;NodejsFunction&lt;/code&gt; construct we were using in our initial implementation.&lt;/p&gt;

&lt;p&gt;We also looked at our Step Function definition and how it needed to be updated to work with our updated Lambda handler code. We used &lt;code&gt;resultSelector&lt;/code&gt; to extract the data we needed from the Lambda function and used it in our Step Function data.&lt;/p&gt;

&lt;p&gt;Updates to the &lt;code&gt;EnergyDrinkSelectorStepFunctionStack&lt;/code&gt; showed us how we could make use of our shiny new custom L3 construct in our stacks and replace the calls to the &lt;code&gt;NodejsFunction&lt;/code&gt; construct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thank You! Yes, You!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bZUeBQL2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8zrc2yuufpbtd4t8irld.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bZUeBQL2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8zrc2yuufpbtd4t8irld.png" alt="An AI generated image showing a big banner saying thank you with people celebrating and showing thanks" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This episode is the last in the series, as we now have a fully working app. Hopefully, you have been able to learn something during the process, even if it’s something small; I’ll take that as a win.&lt;/p&gt;

&lt;p&gt;This series was never meant to be the ‘Let’s CDK’ series to end all ‘Let’s CDK’ series. The aim was to introduce you to AWS CDK and guide you through how to provision, create and deploy AWS resources and create a little app in the process. There is plenty of scope to build upon what we have built so far. It would be really cool to see anything you may want to add. Feel free to fork the &lt;a href="https://github.com/TheLeePriest/lets-cdk-energy-drink-selector"&gt;Github repo&lt;/a&gt; and let me know about anything you create/update!&lt;/p&gt;

&lt;p&gt;Thank you for taking the time to read this series of posts and for putting up with my terrible puns!&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;If you want to look at the code and don’t want to read my ramblings, navigate to &lt;a href="https://github.com/TheLeePriest/lets-cdk-energy-drink-selector"&gt;this Github repo&lt;/a&gt; and spy on everything we’ll be creating in the series.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>typescript</category>
      <category>serverless</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The Energy Drink Episodes 3: The Step Function Awakens</title>
      <dc:creator>Lee Priest</dc:creator>
      <pubDate>Tue, 05 Dec 2023 17:32:14 +0000</pubDate>
      <link>https://dev.to/aws-builders/the-energy-drink-episodes-3-the-step-function-awakens-1kni</link>
      <guid>https://dev.to/aws-builders/the-energy-drink-episodes-3-the-step-function-awakens-1kni</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eFyYSrIV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3rtjchu5w54fdradtt3i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eFyYSrIV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3rtjchu5w54fdradtt3i.png" alt="Image description" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post is the third part of a ‘Let’s CDK’ series. You can catch up on &lt;a href="https://dev.to/aws-builders/lets-cdk-the-energy-drink-episodes-4a4f"&gt;part 1 here&lt;/a&gt; and &lt;a href="https://dev.to/aws-builders/the-energy-drink-episodes-2-the-rise-of-the-amazon-api-gateway-36ea"&gt;part 2 here&lt;/a&gt;. This post is part of a series that will introduce you to the AWS Cloud Development Kit (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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where were we?
&lt;/h2&gt;

&lt;p&gt;In our last episode, we created a logical flow diagram for our app so we are sure of the purpose of the app and the flow we’ll need to achieve it. We also learned about the AWS CDK constructs for API Gateway and created our own custom L3 construct. We then created a stack and initialised our new custom construct to create our REST API. Feel free to have a read-through of the previous episode if you need any refresher before you continue on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are we doing today, Lee?
&lt;/h2&gt;

&lt;p&gt;I’m glad you asked! If we look at the current state of our app, we can see that we’ve got a Stack, a Nested Stack and a REST API. It’s cool that we have those, but if we were to try and call the API, nothing would be invoked, and nothing would really happen. Let’s look at changing that.&lt;/p&gt;

&lt;p&gt;Let’s take another look at our logical flow diagram:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ycvrXf4z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vodyouwq74qu0y4qxkpj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ycvrXf4z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vodyouwq74qu0y4qxkpj.png" alt="The logical flow we want our app to follow" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the moment, we are technically able to receive a request, but we don’t have any way of running logic against the incoming payload. Before diving in and throwing typescript around to create some handlers, let’s first think about what logic we want to run. &lt;a href="https://medium.com/lego-engineering/energise-yourself-with-express-step-functions-6e01b8d86847"&gt;Remember, this app we are building is an ‘Energy drink selector’&lt;/a&gt;, so we want to ensure we include relevant logic gates. Potential logic includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Payload validation: We want to be sure that the payload we receive is valid before we try to do too much with it.&lt;/li&gt;
&lt;li&gt;Sugar vs. Sugar-free: The user wants to be able to have a drink recommendation based on their preference for sugar or sugar-free.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Could We Use?
&lt;/h2&gt;

&lt;p&gt;So, we have our logic needs decided. What AWS services could we use to enable us to run our logic checks? We could pass the payload straight from API Gateway to a Lambda function and then run our logic within that function. This would definitely work, but there are a couple of things that we may want to consider about this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Having the payload validation in a Lambda function is not an issue. However, considering that we may have different validation needs dependent on the payload we receive could impact the size of the Lambda function and cause unnecessary bloat. We could also look at shifting the validation to a point before the lambda function is invoked and have an early return. This would &lt;a href="https://sbrisals.medium.com/think-sustainability-while-developing-serverless-applications-d61a37845914"&gt;save on unnecessary compute&lt;/a&gt; and would also be nicer on our wallets.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The logic for sugar vs. sugar-free would need to be contained within this single Lambda function. Sure, we could add this all in and get it to work, but we need to consider the long-term maintainability of the Lambda function. We should aim to keep our Lambda functions and all of our infrastructure as concise as possible.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Considering the above points, an alternative to a Lambda function could be using AWS Step Functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS Step Functions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--710sx9_5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jl8893205tltd5l3zk0e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--710sx9_5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jl8893205tltd5l3zk0e.png" alt="DALL-E can generate some really trippy images…&amp;lt;br&amp;gt;
" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have ever spoken to me, read anything I've written or listened to any talks I’ve done in relation to Serverless or infrastructure as code, there is a high likelihood that I have confessed my love for Step Functions. Even when unprompted. Putting my biases aside, however, there are some legitimate reasons we can consider using them in our app. If you are new to Step Functions or just fancy a refresher, &lt;a href="https://aws.amazon.com/step-functions/"&gt;have a read about them here&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://aws.amazon.com/step-functions/"&gt;AWS Step Functions&lt;/a&gt; provides serverless orchestration for modern applications. Orchestration centrally manages a workflow by breaking it into multiple steps, adding flow logic, and tracking the inputs and outputs between the steps.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a nutshell, AWS Step Functions lets us create a workflow that we can configure to run various things. It allows us to run checks using flow steps, run actions using baked-in integrations with services like Dynamo DB and 200+ more AWS services, and use pre-built patterns to process S3 objects.&lt;/p&gt;

&lt;p&gt;We could leverage many features baked into Step Functions to tackle the considerations we had above regarding using a single Lambda function.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Payload validation: A ‘Choice’ step would allow us to perform basic validation on the incoming payload. Things like checking that values exist and are of the correct type is something that’s easily possible. We can route to an error handler and exit early for any failed validation.&lt;/li&gt;
&lt;li&gt;Specific routing: Another use of a ‘Choice’ step would be to route the execution based on part of the Step Function input. For example, if the incoming payload had sugar: false set, we could route down a specific path and eliminate running unnecessary compute and other steps.&lt;/li&gt;
&lt;li&gt;We can still use Lambda Functions: For any logic that is a bit more in-depth, we can invoke a lambda function and pass in the payload via the Step Function. Combined with the “specific routing” mentioned above, we can create very concise Lamba functions with dedicated logic for that particular route.&lt;/li&gt;
&lt;li&gt;Storage first pattern: We could also easily employ a storage first pattern using the built-in Dynamo DB integration. &lt;a href="https://www.jeremydaly.com/the-storage-first-pattern/"&gt;Jeremy Daly has a great article detailing the storage first pattern&lt;/a&gt;. Using this pattern will allow us to capture the raw input to the step function and potentially handle things like retries and a number of other things if needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With everything I’ve mentioned above and the article's title, you have probably worked out that we will use a Step Function rather than a single Lambda function to handle the ‘Run logic against request payload’ part of our logical flow.&lt;/p&gt;
&lt;h2&gt;
  
  
  Something to Consider
&lt;/h2&gt;

&lt;p&gt;Step Functions come in two different ‘flavours’, or for the official term, workflow types. These two different types are standard and express.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard: This type of Step Function workflow is ideal for long-running workflows and can run for up to one year. They are billed by state transition and can use things like &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-resource.html#connect-wait-token"&gt;task tokens&lt;/a&gt; to enable the ‘pausing’ of an execution while another task is completed and a response is received.&lt;/li&gt;
&lt;li&gt;Express: This type of Step Function workflow is ideal for high-volume, event-processing workflows and can run for up to five minutes. Express Step Functions are billed by the number of executions, duration of execution and the memory consumed while the execution ran. Express Step Function workflows can return synchronous responses when configured with &lt;code&gt;StartSyncExecution&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s now consider which type of workflow suits our needs the best. The payload we expect will be small and won't need much processing done to it. We won’t have any other microservices or third-party integrations to contact, so we won’t need a &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-resource.html#connect-wait-token"&gt;task token&lt;/a&gt;. We need to ensure that we can send a synchronous response back to the client that called so we can return their drink recommendation. Given the descriptions above, it looks like an Express workflow is the way to go!&lt;/p&gt;
&lt;h2&gt;
  
  
  Wait a Minute…
&lt;/h2&gt;

&lt;p&gt;Before we create our Express Step Function, we need to make sure that we have the resources it will need to run, or at least some placeholders that we can flesh out later. As we are going to run a storage-first pattern, we will need to set up a Dynamo DB table. We will also need a couple of Lambda Functions to be able to run some logic against the incoming payload.&lt;/p&gt;

&lt;p&gt;Let’s jump back into our code and open up &lt;code&gt;energy-drink-selector-stack.ts&lt;/code&gt; in the &lt;code&gt;lib&lt;/code&gt; directory. We currently have our API Gateway stack and a &lt;code&gt;GET&lt;/code&gt; method setup that’s not really doing much. We can remove that &lt;code&gt;GET&lt;/code&gt; method, as we’ll be hooking up our step function later.&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding Our Dynamo DB Table
&lt;/h2&gt;

&lt;p&gt;If you aren’t too familiar with Dynamo DB, I would definitely suggest having a r&lt;a href="https://docs.aws.amazon.com/dynamodb/"&gt;ead over the documentation&lt;/a&gt;. We aren’t going to be getting too in-depth with Dynamo DB, but we will be creating a table and &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html"&gt;running a &lt;code&gt;PutItem&lt;/code&gt;&lt;/a&gt; call to store our incoming payload.&lt;/p&gt;

&lt;p&gt;In order to create a new Dynamo DB table using CDK, we can &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_dynamodb.Table.html"&gt;refer to the documentation&lt;/a&gt; and see that there is a &lt;code&gt;Table&lt;/code&gt; construct that we can use. Let’s use that &lt;code&gt;Table&lt;/code&gt; construct to create our table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const energyDrinkTable = new Table(this, 'EnergyDrinkDynamoTable', {
  tableName: 'EnergyDrinkTable',
  billingMode: BillingMode.PAY_PER_REQUEST,
  partitionKey: {
      name: 'PK',
      type: AttributeType.STRING
  },
  sortKey: {
      name: 'SK',
      type: AttributeType.STRING
  }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code snippet above, there are a few things we can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We initialise the &lt;code&gt;Table&lt;/code&gt; construct and pass it the &lt;code&gt;this&lt;/code&gt; value as its scope. Remember, this refers to our &lt;code&gt;EnergyDrinkSelectorStack&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For the second argument, we pass a logical ID&lt;/li&gt;
&lt;li&gt;We set the tableName property to ‘EnergyDrinkTable’ to avoid using an autogenerated name provided by CDK. Just make sure that this value is always unique to avoid deployment headaches and other issues.&lt;/li&gt;
&lt;li&gt;We then specify both a &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html"&gt;partition key and a sort key&lt;/a&gt; as &lt;code&gt;PK&lt;/code&gt; and &lt;code&gt;SK&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So now our &lt;code&gt;EnergyDrinkSelectorStack&lt;/code&gt; should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { APIGatewayStack } from '../stacks/APIGatewayStack';
import { AttributeType, Table, BillingMode } from 'aws-cdk-lib/aws-dynamodb';

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

    const apiGatewayStack = new APIGatewayStack(this, 'EnergyDrinkSelectorAPIGatewayStack');

    const energyDrinkTable = new Table(this, 'EnergyDrinkDynamoTable', {
      tableName: 'EnergyDrinkTable',
      billingMode: BillingMode.PAY_PER_REQUEST,
      partitionKey: {
          name: 'PK',
          type: AttributeType.STRING
      },
      sortKey: {
          name: 'SK',
          type: AttributeType.STRING
      }
    });

  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And with that, we now have our Dynamo DB table configured! When we next deploy, CDK will synthesise a CloudFormation template and create the Dynamo DB table for us.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s Add Some Placeholders For Now…
&lt;/h2&gt;

&lt;p&gt;So we have our shiny new Dynamo DB table configured. Let’s now turn our attention to the Lambda Functions. For the time being, we can set up some placeholder functions that won't do much but will allow us to configure our Step Function. We can always come back to the Lambda Functions later and flesh them out with whatever logic we need.&lt;/p&gt;

&lt;p&gt;At the root of our project, let's add a &lt;code&gt;src&lt;/code&gt; directory and, within that, a &lt;code&gt;functions&lt;/code&gt; directory. This is where all of our Lambda Functions will live. Let’s also create a directory per Lambda Function. So, in our case, let’s create a &lt;code&gt;sugar&lt;/code&gt; and &lt;code&gt;sugarFree&lt;/code&gt; directory inside our &lt;code&gt;functions&lt;/code&gt; directory. So our structure should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
│
└───functions/
    │
    ├───sugar/
    │
    └───sugarFree/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can’t do too much with empty directories, let’s add a file to each one. Add a &lt;code&gt;sugar.ts&lt;/code&gt; and a &lt;code&gt;sugarFree.ts&lt;/code&gt; file in their respective directories. For the actual code in the &lt;code&gt;.ts&lt;/code&gt; files, we are just going to have a very basic placeholder that will return a message. We can use the following code for our handler. Just make sure to update the name (sugar to sugarFree) and the message to match the file they are in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const sugar = async () =&amp;gt; {
    return {
        statusCode: 200,
        body: {
          message: "Hello, Sugar World!"
        },
    };
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, we now have our Dynamo DB table and placeholder handler functions. We have everything we need to start building our Step Function!&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s Get Stepping!
&lt;/h2&gt;

&lt;p&gt;There are a few different ways that you can build out Step Functions using CDK. One way we could approach it is by taking the JSON generated by the Workflow Studio and passing it as the &lt;code&gt;definitionBody&lt;/code&gt; to the &lt;code&gt;StateMachine&lt;/code&gt; construct. There is nothing wrong with this approach, and you can even set up some cool integrations in &lt;a href="https://aws.amazon.com/blogs/compute/aws-step-functions-support-in-visual-studio-code/"&gt;VS Code to visualise your step function&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The way we are going to approach our Step Function creation is to build out our definition ourselves using the various classes and constructs made available to use via the &lt;code&gt;aws-cdk-lib&lt;/code&gt; library. Our first step on this journey is to create our own L3 construct so we can create our own express step function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Construct
&lt;/h2&gt;

&lt;p&gt;Remember our &lt;code&gt;constructs&lt;/code&gt; directory from the previous episode? Let’s head back there and create a new directory called &lt;code&gt;StepFunctions&lt;/code&gt;. Inside that directory, create a new file called &lt;code&gt;ExpressStepFunction.ts&lt;/code&gt;. Within our newly created file, let’s first add the imports we’ll be needing. These are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Stack, Duration } from 'aws-cdk-lib';
import { LogGroup } from 'aws-cdk-lib/aws-logs';
import { Construct } from 'constructs';
import { 
  StateMachine, 
  DefinitionBody, 
  IChainable, 
  StateMachineType, 
  LogLevel 
} from 'aws-cdk-lib/aws-stepfunctions';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A quick look at the imports above shows that we are importing the &lt;code&gt;Stack&lt;/code&gt; construct and the &lt;code&gt;Duration&lt;/code&gt; class. The &lt;code&gt;Stack&lt;/code&gt; will be used when assigning the type of the scope for our custom construct. &lt;code&gt;Duration&lt;/code&gt; will be used to set the timeout duration. Importing &lt;code&gt;LogGroup&lt;/code&gt; will allow us to create a new log group so we have some observability on our step function. As we’re creating our own custom construct, we need to extend the base &lt;code&gt;Construct&lt;/code&gt; provided by the constructs library. Our final line of imports sees us importing all the fun things needed to initialise the &lt;code&gt;StateMachine&lt;/code&gt; and ensure it has the correct typings and parameters set.&lt;/p&gt;

&lt;p&gt;We can re-use the bare bones template we used when creating our &lt;code&gt;APIGateway&lt;/code&gt; construct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class ExpressStepFunction extends Construct {
    constructor(scope: Stack, id: string, props: ExpressStepFunctionProps) {
        super(scope, id);

        // This is where we're gonna have some fun!        

    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we start having the proper fun of fleshing out the construct, we need to define the &lt;code&gt;ExpressStepFunctionProps&lt;/code&gt; type. Above the export, let’s add the following type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type ExpressStepFunctionProps = {
    serviceName: string;
    stage: string;
    definition: IChainable;
    timeout?: number;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have seen the &lt;code&gt;serviceName&lt;/code&gt; and &lt;code&gt;stage&lt;/code&gt; props before in our &lt;code&gt;ApiGateway&lt;/code&gt; construct. But we now have two new parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;definition: Typed as &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_stepfunctions.IChainable.html"&gt;IChainable&lt;/a&gt;. This will be the actual definition of the steps the step function should take. As the name suggests, the definition will consist of a bunch of chainable states.&lt;/li&gt;
&lt;li&gt;timeout: Typed as a number. This number will be passed to the &lt;code&gt;Duration&lt;/code&gt; we imported earlier, allowing us to specify a default or a specific timeout value for a given step function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, we can have some fun fleshing out the construct. Let’s first destructure some variables from our &lt;code&gt;props&lt;/code&gt; object and set up a new &lt;code&gt;LogGroup&lt;/code&gt; for the Step Function. We can do this as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const {
    serviceName,
    stage,
    definition,
    timeout = 5
} = props;

const logGroup = new LogGroup(
  this, 
  `${serviceName}-express-stepfn-logs-${stage}`
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the &lt;code&gt;LogGroup&lt;/code&gt; class, we created a new Cloudwatch log group that we can pass to the Step Function. I find it pretty cool that creating a log group is so easy, and hopefully, you do too! All we need to do is pass the scope, which is our Step Function construct, and the name of the log group, and CDK will work its magic at synth time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;note: If you get an error when trying to deploy relating to the LogGroup name, you may need to prefix the log group name. &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/cw-logs.html"&gt;You can read more here.&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Creating the actual state machine is also fairly straightforward. We can use the &lt;code&gt;StateMachine&lt;/code&gt; construct and a few arguments, and we’re good to go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.stateMachine = new StateMachine(
  this, 
  `${serviceName}-express-stepfn-${stage}`, 
  {
     definitionBody: DefinitionBody.fromChainable(definition),
     timeout: Duration.minutes(timeout),
     stateMachineType: StateMachineType.EXPRESS,
     stateMachineName: `${serviceName}-express-stepfn-${stage}`,
     logs: {
      destination: logGroup,
      level: LogLevel.ALL,
      includeExecutionData: true
     }
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s break down the &lt;code&gt;StateMachine&lt;/code&gt; call above and the arguments passed to it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;this: The scope of the &lt;code&gt;StateMachine&lt;/code&gt;, which, in this case, is our new &lt;code&gt;Construct&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;${serviceName}-express-stepfn-${stage}: This is the string we’re passing as the logical ID. We use template strings to allow us to use variables to build the name dynamically. This could be expanded to take another variable like &lt;code&gt;stepFunctionName&lt;/code&gt; or something similar to allow for more granularity. But for our current needs, it’s fine as is.&lt;/li&gt;
&lt;li&gt;definitionBody: The ‘meat’ of our Step Function. This will be a chain of steps we pass that will be used to build out the steps in the Step Function.&lt;/li&gt;
&lt;li&gt;timeout: The maximum &lt;code&gt;Duration&lt;/code&gt; of time the Step Function can run for. We default this to 5, the default for an Express workflow.&lt;/li&gt;
&lt;li&gt;stateMachineType: This is where we explicitly specify the Step Function type to be &lt;code&gt;express&lt;/code&gt;. We do this using the &lt;code&gt;StateMachineType.EXPRESS&lt;/code&gt; enum.&lt;/li&gt;
&lt;li&gt;stateMachineName: Not to be confused with the logical ID. This is the name of the step function. So, if we’re looking in the AWS console, we can easily find it, as it won't be an auto-generated name given by CDK.&lt;/li&gt;
&lt;li&gt;logs: This object allows us to specify our logging configuration for the Step Function. We pass the log group we created earlier as the destination for the logs. We also specify the level to be the enum LogLevel.ALL meaning that everything will get logged, not just errors or nothing at all. Setting &lt;code&gt;includeExecutionData&lt;/code&gt; to true allows us to see the execution data in our logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An important thing to note when setting the logs object in your real-world applications:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please be careful and don’t include any sensitive or PII data in your logs!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Let’s Get Defining!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--krZD10Bi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s47on61n1tmghwbyp6tk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--krZD10Bi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s47on61n1tmghwbyp6tk.png" alt="DALL-E can generate some wild images…" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have our shiny new L3 Step Function construct, and now we need some actual step definitions to put it to good use. Let’s create a new directory in our &lt;code&gt;src&lt;/code&gt; directory called &lt;code&gt;stepFunctions&lt;/code&gt;. In the future, we may have some other fun things related to Step Functions in the directory, so let’s create a directory called &lt;code&gt;definitions&lt;/code&gt; in this &lt;code&gt;stepFunctions&lt;/code&gt; directory. With our directories created, let’s create a file called &lt;code&gt;energyDrinkSelector.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As we’ve done before, let’s start by looking at the imports we’ll need to create our definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { 
  Pass, 
  Choice, 
  Fail, 
  JsonPath, 
  Condition 
} from "aws-cdk-lib/aws-stepfunctions";
import { 
  LambdaInvoke, 
  DynamoPutItem, 
  DynamoAttributeValue 
} from "aws-cdk-lib/aws-stepfunctions-tasks";
import { Stack } from 'aws-cdk-lib';
import { ITable } from 'aws-cdk-lib/aws-dynamodb';
import { IFunction } from "aws-cdk-lib/aws-lambda";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I won’t go through all of them, but you can see that we are importing various things from &lt;code&gt;aws-cdk-lib/aws-stepfunctions&lt;/code&gt; and &lt;code&gt;aws-cdk-lib/aws-stepfunctions-tasks&lt;/code&gt;. These refer to the flow steps (Pass, Choice, Fail, Condition) and integration tasks (LambdaInvoke, DynamoPutItem) we can use within Step Functions.&lt;/p&gt;

&lt;p&gt;As we are still within the realm of Typescript, we need to define our type for the props the definition creation function we will create will receive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type energyDrinkSelectorDefinitionProps = {
    stack: Stack
    energyDrinkTable: ITable,
    sugarFreeLambdaFunction: IFunction,
    sugarLambdaFunction: IFunction
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have the usual &lt;code&gt;stack&lt;/code&gt; prop so that we can scope things correctly. We also are going to be passing the Dynamo DB table and Lambda Functions we created earlier.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Definition Creator Function
&lt;/h2&gt;

&lt;p&gt;Next, we can set up a function to create and return our definition. Let’s start by defining the function and the props it will receive based on the type we just defined:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const energyDrinkSelectorDefinition = ({
    stack,
    energyDrinkTable,
    sugarFreeLambdaFunction,
    sugarLambdaFunction
}: energyDrinkSelectorDefinitionProps) =&amp;gt; {

  // Looking mighty empty in here...

};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above won’t get us too far, so let’s start adding things. The first thing we can do is create a call to Dynamo DB to store the ‘raw’ input received by the Step Function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const storeRawItem = new DynamoPutItem(
  stack, 
  'StoreRawItem', 
  {
    item: {
        PK: DynamoAttributeValue.fromString(JsonPath.uuid()),
        SK: DynamoAttributeValue.fromString('RAWITEM'),
        body: DynamoAttributeValue.fromString(JsonPath.jsonToString(JsonPath.objectAt('$'))),
    },
    table: energyDrinkTable,
    resultPath: '$.dynamoResult'
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above may look a little odd, especially in the &lt;code&gt;item&lt;/code&gt; object, but we can break it down to remove the fear. Initialising the &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_stepfunctions_tasks.DynamoPutItem.html"&gt;&lt;code&gt;DynamoPutItem&lt;/code&gt;&lt;/a&gt; class, we pass the &lt;code&gt;stack&lt;/code&gt; to ensure correct scoping, a logical ID and a &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_stepfunctions_tasks.DynamoPutItemProps.html"&gt;props object&lt;/a&gt;. Within the props object, we can specify the fields of the item we want to create. As this call will be storing the ‘raw’ input, we are creating a ‘body’ parameter on the item object that will store the entire input passed to the step function execution.&lt;/p&gt;

&lt;p&gt;All that scary-looking code on the body line, looking at &lt;code&gt;youJsonPath&lt;/code&gt;, is how we can access the state of the execution and format it to a type that Dynamo DB is happy with. We use the &lt;code&gt;objectAt&lt;/code&gt; method to find the object at the location &lt;code&gt;$&lt;/code&gt;. In step function land, the &lt;code&gt;$&lt;/code&gt; represents the root of the execution state. So, accessing the object at this location will allow us to get the entire execution state. The &lt;code&gt;jsonToString&lt;/code&gt; method is also used to make sure everything plays nicely with the &lt;code&gt;DynamoAttributeValue&lt;/code&gt; and the item object matches what the &lt;code&gt;DynamoPutItem&lt;/code&gt; method expects.&lt;/p&gt;

&lt;p&gt;We pass the &lt;code&gt;energyDrinkTable&lt;/code&gt; reference to the &lt;code&gt;table&lt;/code&gt; parameter on the props object. This will ensure that when the execution runs, it stores the item in the correct Dynamo DB table. We will also use &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/input-output-resultpath.html"&gt;&lt;code&gt;resultPath&lt;/code&gt;&lt;/a&gt; with our storage call and set that to store the result of the &lt;code&gt;DynamoPutItem&lt;/code&gt; call in an object on the execution state called &lt;code&gt;dynamoResult&lt;/code&gt;. This &lt;code&gt;dynamoResult&lt;/code&gt; object could then be accessed at any point in the execution as it is made part of the execution state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the Definition Chain
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KXh_6gPE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hkqodv5dgukbqdhp1eg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KXh_6gPE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hkqodv5dgukbqdhp1eg7.png" alt="All aboard the energy train" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have our storage action setup, we can start looking at creating the actual step function definition chain. The definition chain is where we will define things like our &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-choice-state.html"&gt;&lt;code&gt;Choice&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-pass-state.html"&gt;&lt;code&gt;Pass&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-fail-state.html"&gt;&lt;code&gt;Fail&lt;/code&gt;&lt;/a&gt; states. We will also set our catch blocks for catching errors and specify when our Lambda Functions should be invoked. We can create our definition chain by doing the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const validatePayload = new Choice(stack, 'Validate Payload');
const isSugarFree = new Choice(stack, 'Sugar vs Sugar Free');
const sugarFreePassState = new Pass(stack, 'Sugar Free Error', {});
const sugarPassState = new Pass(stack, 'Sugar Error', {});
const failState = new Fail(stack, 'Fail', {});

const definition = storeRawItem.addCatch(failState).next(
    validatePayload
        .when(Condition.isPresent('$.sugar'), isSugarFree
            .when(Condition.booleanEquals('$.sugar', true), new LambdaInvoke(stack, 'Sugar Logic', {
                lambdaFunction: sugarLambdaFunction,
            }).addCatch(sugarPassState, { errors: ['States.ALL'] }))
            .otherwise(new LambdaInvoke(stack, 'Sugar Free Logic', {
                lambdaFunction: sugarFreeLambdaFunction,
            }).addCatch(sugarFreePassState, { errors: ['States.ALL'] }))
        )
        .otherwise(failState)
);

return definition;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see in the example above that we create the states that we will be needing for the execution and pass them the &lt;code&gt;stack&lt;/code&gt; as their scope. We also pass in the name of the state.&lt;/p&gt;

&lt;p&gt;After creating the states we need, we create the Step Function definition. The &lt;code&gt;storeRawItem&lt;/code&gt; is called first to ensure we follow our storage first pattern, and then a &lt;code&gt;.next&lt;/code&gt; allows us to chain on the next step in the Step Function. The &lt;code&gt;validatePayload&lt;/code&gt; &lt;code&gt;Choice&lt;/code&gt; state is run and checks for the existence of a sugar variable being present in the execution state. If the &lt;code&gt;sugar&lt;/code&gt; variable is found, the chain continues on to the &lt;code&gt;isSugarFree&lt;/code&gt; check. The &lt;code&gt;.otherWise&lt;/code&gt; is used when conditions aren’t met. So, in this case, there is a &lt;code&gt;.otherWise&lt;/code&gt; to go to the &lt;code&gt;failState&lt;/code&gt; if the &lt;code&gt;sugar&lt;/code&gt; variable is not present, and another to go to the &lt;code&gt;LambdaInvoke&lt;/code&gt; of the sugar-free logic function if the sugar variable is found not to be set to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If all has gone to plan, you should end up with a definition create function file that looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Pass, Choice, Fail, JsonPath, Condition } from "aws-cdk-lib/aws-stepfunctions";
import { LambdaInvoke, DynamoPutItem, DynamoAttributeValue } from "aws-cdk-lib/aws-stepfunctions-tasks";
import { Stack, Token } from 'aws-cdk-lib';
import { ITable } from 'aws-cdk-lib/aws-dynamodb';
import { IFunction } from "aws-cdk-lib/aws-lambda";

type energyDrinkSelectorDefinitionProps = {
    stack: Stack
    energyDrinkTable: ITable,
    sugarFreeLambdaFunction: IFunction,
    sugarLambdaFunction: IFunction
}

export const energyDrinkSelectorDefinition = ({
    stack,
    energyDrinkTable,
    sugarFreeLambdaFunction,
    sugarLambdaFunction
}: energyDrinkSelectorDefinitionProps) =&amp;gt; {
    const rawItemSK = JsonPath.stringAt('$.sugar') === 'true' ? 'SUGAR' : 'SUGAR_FREE';
    const storeRawItem = new DynamoPutItem(stack, 'StoreRawItem', {
        item: {
            PK: DynamoAttributeValue.fromString(JsonPath.format(`RAWITEM#{}`, JsonPath.uuid())),
            SK: DynamoAttributeValue.fromString(rawItemSK),
            body: DynamoAttributeValue.fromString(JsonPath.jsonToString(JsonPath.objectAt('$'))),
        },
        table: energyDrinkTable,
        resultPath: '$.dynamoResult'
    });

    const validatePayload = new Choice(stack, 'Validate Payload');
    const isSugarFree = new Choice(stack, 'Sugar vs Sugar Free');
    const sugarFreePassState = new Pass(stack, 'Sugar Free Error', {});
    const sugarPassState = new Pass(stack, 'Sugar Error', {});
    const failState = new Fail(stack, 'Fail', {});

    const definition = storeRawItem.addCatch(failState).next(
        validatePayload
            .when(Condition.isPresent('$.sugar'), isSugarFree
                .when(Condition.booleanEquals('$.sugar', true), new LambdaInvoke(stack, 'Sugar Logic', {
                    lambdaFunction: sugarLambdaFunction,
                }).addCatch(sugarPassState, { errors: ['States.ALL'] }))
                .otherwise(new LambdaInvoke(stack, 'Sugar Free Logic', {
                    lambdaFunction: sugarFreeLambdaFunction,
                }).addCatch(sugarFreePassState, { errors: ['States.ALL'] }))
            )
            .otherwise(failState)
    )

    return definition;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Let’s Stack That Step
&lt;/h2&gt;

&lt;p&gt;Now that we have our Step Function definition, we can turn our attention to creating a stack where our Step Function can live. In the &lt;code&gt;stacks&lt;/code&gt; directory of the project, create a new file called &lt;code&gt;EnergyDrinkSelectorStepFunctionStack.ts&lt;/code&gt;. Continuing the tradition we have established so far, let’s take a look at the imports we’ll need for our &lt;code&gt;EnergyDrinkSelectorStepFunctionStack&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import path = require("path");
import { Construct } from "constructs";
import { NestedStack, NestedStackProps } from "aws-cdk-lib";
import { StateMachine } from "aws-cdk-lib/aws-stepfunctions";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Architecture, Runtime } from "aws-cdk-lib/aws-lambda";
import { ITable } from "aws-cdk-lib/aws-dynamodb";
import { ExpressStepFunction } from "../constructs/StepFunctions/ExpressStepFunction";
import { energyDrinkSelectorDefinition } from "../src/stepFunctions/definitions/energyDrinkSelector";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s take a quick look at some of the imports above that we haven’t used yet in this series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;path: We’ll need this to build out some paths that are needed for our Lambda Functions&lt;/li&gt;
&lt;li&gt;NodejsFunction: &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs.NodejsFunction.html"&gt;This class can be used to build a Node.js Lambda Function bundled with esbuild&lt;/a&gt;. There are a few reasons to use this over &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.Function.html"&gt;the Function class&lt;/a&gt;. One of the primary ones for us is that the NodejsFunction simplifies the development process when working with typescript.&lt;/li&gt;
&lt;li&gt;Architecture &amp;amp; Runtime: These are used to specify what architecture and runtime we want our Lambda Functions to use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, let’s create the stack skeleton as we have previously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type EnergyDrinkSelectorStepFunctionStackProps = NestedStackProps &amp;amp; {
    table: ITable;
}

export class EnergyDrinkSelectorStepFunctionStack extends NestedStack {
    constructor(scope: Construct, id: string, props: EnergyDrinkSelectorStepFunctionStackProps) {
        super(scope, id, props);

        const { table } = props;

        // fun things live in here

    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we first create a type for our props object that is passed into the stack. We take the &lt;code&gt;NestedStackProps&lt;/code&gt; object and extend it to also contain a &lt;code&gt;table&lt;/code&gt; parameter. Hopefully, this stack skeleton is looking quite familiar. We have the &lt;code&gt;EnergyDrinkSelectorStepFunctionStack&lt;/code&gt; extending the &lt;code&gt;NestedStack&lt;/code&gt; and the familiar &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor"&gt;constructor&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super"&gt;super&lt;/a&gt; calls.&lt;/p&gt;

&lt;p&gt;As we have realised, having the skeleton is great, but we want to have a bit more fun than just building a skeleton stack. Let’s look at adding some meat to this skeleton by defining our express step function and any props it may need. Remember when we created those placeholder Lambda Function handler files? Well, now we get to make use of them. Seeing as we’ll need them in our express step function and the function we created to build out the Step Function definition requires them as props, we will need to build out our Lambda Functions to pass down. We are able to do this as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sugarFreeLambdaFunction = new NodejsFunction(this, 'SugarFreeLambdaFunction', {
    entry: path.join(__dirname, '../src/functions/sugarFree/sugarFree.ts'),
    runtime: Runtime.NODEJS_18_X,
    architecture: Architecture.ARM_64,
    handler: 'sugarFree',
    bundling: {
        sourceMap: true,
        minify: true,
        tsconfig: path.join(__dirname, '../tsconfig.json'),
    },
});

const sugarLambdaFunction = new NodejsFunction(this, 'SugarLambdaFunction', {
    entry: path.join(__dirname, '../src/functions/sugar/sugar.ts'),
    runtime: Runtime.NODEJS_18_X,
    architecture: Architecture.ARM_64,
    handler: 'sugar',
    bundling: {
        sourceMap: true,
        minify: true,
        tsconfig: path.join(__dirname, '../tsconfig.json'),
    },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breaking down the code above, we can see that we’re initialising the &lt;code&gt;NodejsFunction&lt;/code&gt; class and passing it the scope (&lt;code&gt;this&lt;/code&gt; which refers to our stack) and a logical ID. Then, in the props object, we can see we are passing an entry path. This entry path is the path to the Lambda Function handler we created earlier.&lt;/p&gt;

&lt;p&gt;The runtime and architecture parameters allow us to choose the runtime and architecture we want the Lambda Function to run on.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;handler&lt;/code&gt; parameter finds the actual handler function inside the file we specified in the entry path. So, in our case, we need to specify &lt;code&gt;sugarFree&lt;/code&gt; or &lt;code&gt;sugar&lt;/code&gt; as these are the function names specified in the handler files.&lt;/p&gt;

&lt;p&gt;The bundling object allows us to control how the Lambda Function is bundled, and we are able to pass our &lt;code&gt;tsconfig.json&lt;/code&gt; file so our typescript configuration can be understood.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const energyDrinkSelectorStepFunction = new ExpressStepFunction(this, 'EnergyDrinkSelectorExpress', {
    serviceName: 'energy-drink-selector',
    stage: 'dev',
    definition: energyDrinkSelectorDefinition({
        stack: this,
        energyDrinkTable: table,
        sugarLambdaFunction: sugarLambdaFunction, 
        sugarFreeLambdaFunction: sugarFreeLambdaFunction
    })
});

this.stepFunction = energyDrinkSelectorStepFunction.stateMachine;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialising our custom ExpressStepFunction construct, we pass it the scope, logical ID, and props object. The &lt;code&gt;serviceName&lt;/code&gt; and &lt;code&gt;stage&lt;/code&gt; parameters are pretty straightforward as they’re just strings. We get to have some fun creating the definition as we can leverage our &lt;code&gt;energyDrinkSelectorDefinition&lt;/code&gt; function. We pass it the stack, the table we destructured from our stack props object and our Lambda Functions. We then assign the &lt;code&gt;stateMachine&lt;/code&gt; generated from the construct to a public variable in the stack to make it accessible to other things that may need it. As we’re assigning to a public variable, we need to ensure that we have declared it. We can add the following just after the start of the stack definition before the constructor call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public readonly stepFunction: StateMachine;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we should now have an &lt;code&gt;EnergyDrinkSelectorStepFunctionStack&lt;/code&gt; that looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import path = require("path");
import { Construct } from "constructs";
import { NestedStack, NestedStackProps } from "aws-cdk-lib";
import { StateMachine } from "aws-cdk-lib/aws-stepfunctions";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Architecture, Runtime } from "aws-cdk-lib/aws-lambda";
import { ITable } from "aws-cdk-lib/aws-dynamodb";
import { ExpressStepFunction } from "../constructs/StepFunctions/ExpressStepFunction";
import { energyDrinkSelectorDefinition } from "../src/stepFunctions/definitions/energyDrinkSelector";

type EnergyDrinkSelectorStepFunctionStackProps = NestedStackProps &amp;amp; {
    table: ITable;
}

export class EnergyDrinkSelectorStepFunctionStack extends NestedStack {
    public readonly stepFunction: StateMachine;

    constructor(scope: Construct, id: string, props: EnergyDrinkSelectorStepFunctionStackProps) {
        super(scope, id, props);

        const { table } = props;

        const sugarFreeLambdaFunction = new NodejsFunction(this, 'SugarFreeLambdaFunction', {
            entry: path.join(__dirname, '../src/functions/sugarFree/sugarFree.ts'),
            runtime: Runtime.NODEJS_18_X,
            architecture: Architecture.ARM_64,
            handler: 'sugarFree',
            bundling: {
                sourceMap: true,
                minify: true,
                tsconfig: path.join(__dirname, '../tsconfig.json'),
            },
        });

        const sugarLambdaFunction = new NodejsFunction(this, 'SugarLambdaFunction', {
            entry: path.join(__dirname, '../src/functions/sugar/sugar.ts'),
            runtime: Runtime.NODEJS_18_X,
            architecture: Architecture.ARM_64,
            handler: 'sugar',
            bundling: {
                sourceMap: true,
                minify: true,
                tsconfig: path.join(__dirname, '../tsconfig.json'),
            },
        });

        const energyDrinkSelectorStepFunction = new ExpressStepFunction(this, 'EnergyDrinkSelectorExpress', {
            serviceName: 'energy-drink-selector',
            stage: 'dev',
            definition: energyDrinkSelectorDefinition({
                stack: this,
                energyDrinkTable: table,
                sugarLambdaFunction: sugarLambdaFunction, 
                sugarFreeLambdaFunction: sugarFreeLambdaFunction
            }),
        });

        this.stepFunction = energyDrinkSelectorStepFunction.stateMachine;
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  We’re almost ready to deploy
&lt;/h2&gt;

&lt;p&gt;We now have the vast majority of elements we need to deploy our shiny new express Step Function successfully. What is left now is to ensure that these new elements are added to our &lt;code&gt;EnergyDrinkSelectorStack&lt;/code&gt; so they are picked up when we run our deployment.&lt;/p&gt;

&lt;p&gt;Let’s start by adding our new Step Function stack to the &lt;code&gt;EnergyDrinkSelectorStack&lt;/code&gt;. We can do this by adding an import to the &lt;code&gt;energy-drink-selector-stack.ts&lt;/code&gt; in the lib directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { EnergyDrinkSelectorStepFunctionStack } from '../stacks/EnergyDrinkSelectorStepFunctionStack';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have the import, we can then add the following line of code underneath our &lt;code&gt;energyDrinkTable&lt;/code&gt; variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const stepFunctionStack = new EnergyDrinkSelectorStepFunctionStack(this, 'EnergyDrinkSelectorStepFunctionStack', { table: energyDrinkTable });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By adding this line of code, we could technically run the &lt;code&gt;cdk deploy&lt;/code&gt; command, and everything would be synthesised and deploy fine. However, there are a few things we still need to consider.&lt;/p&gt;

&lt;p&gt;As we want to trigger the Step Function via API Gateway, we need to ensure that API Gateway has permission to actually invoke the Step Function execution. So, we need to create an &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html"&gt;IAM role&lt;/a&gt; that defines what API Gateway is allowed to do. Of course, AWS CDK has constructs we can use to do this. Let’s get these imported into our &lt;code&gt;energy-drink-selector-stack.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { PolicyDocument, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
import { AwsIntegration } from "aws-cdk-lib/aws-apigateway";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the constructs from the above imports, we can create a new IAM role by adding the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const apiGatewayStepFunctionRole = new Role(this, 'APIGatewayStepFunctionRole', {
  assumedBy: new ServicePrincipal('apigateway.amazonaws.com'),
  inlinePolicies: {
    'StepFunctionsStartSyncExecutionPolicy': new PolicyDocument({
      statements: [
        new PolicyStatement({
          actions: ['states:StartSyncExecution'],
          resources: [stepFunctionStack.stepFunction.stateMachineArn],
        }),
      ],
    }),
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can break down the code snippet above as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;new Role: This initialises the construct and we pass the scope (our stack) and a Role Name of ‘APIGatewayStepFunctionRole’&lt;/li&gt;
&lt;li&gt;assumedBy: This allows us to set the &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html"&gt;principal that is allowed to assume the IAM role&lt;/a&gt;. In our case, here it is the API Gateway service so we pass the string of apigateway.amazonaws.com&lt;/li&gt;
&lt;li&gt;inlinePolicies: This object allows us to create a &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html"&gt;new IAM policy&lt;/a&gt; inline in our role definition. We give the policy the name of ‘StepFunctionsStartSyncExecutionPolicy’ and then set the PolicyDocument and PolicyStatement.&lt;/li&gt;
&lt;li&gt;PolicyDocument: Used to define the permissions and statements within the inline policy&lt;/li&gt;
&lt;li&gt;PolicyStatement: Defines a single permission statement. In our case, it grants the action of ‘states:StartSyncExecution’ to the resources that match the ARN of our express Step Function (stepFunctionStack.stepFunction.stateMachineArn).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we have the role, we need to attach it to our Step Function. We can do this by using the &lt;code&gt;grantStartExecution&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stepFunctionStack.stepFunction.grantStartExecution(apiGatewayStepFunctionRole);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final two things we need to do to allow API Gateway to play nicely with the express Step Function we have created are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add an integration between the API Gateway and the step function using the &lt;code&gt;StartSyncExecution&lt;/code&gt; action.&lt;/li&gt;
&lt;li&gt;Add a POST method to our API to post payloads to it and trigger the Step Function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To create the integration, we can use the &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.AwsIntegration.html"&gt;AwsIntegration class&lt;/a&gt;. We can specify the service and action we want to use in the integration and things like the request and response templates. It looks a little something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const integration = new AwsIntegration({
  service: 'states',
  action: 'StartSyncExecution',
  integrationHttpMethod: 'POST',
  options: {
    credentialsRole: apiGatewayStepFunctionRole,
    requestTemplates: {
      'application/json': `
        {
          "stateMachineArn": "${stepFunctionStack.stepFunction.stateMachineArn}",
          "input": "$util.escapeJavaScript($input.json('$'))"
        }
      `,
    },
    integrationResponses: [
      {
        statusCode: '200',
        responseTemplates: {
          'application/json': `$input.path('$.output')`,
        },
      },
      {
        statusCode: '400',
        selectionPattern: '4\\d{2}',
      },
      {
        statusCode: '500',
        selectionPattern: '5\\d{2}',
      },
    ],
  },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within the &lt;code&gt;options&lt;/code&gt; object, there are a few things we need to be aware of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;credentialsRole: This specifies the IAM role we want the API Gateway to assume. We pass it &lt;code&gt;apiGatewayStepFunctionRole&lt;/code&gt; to ensure it has the necessary permissions for interacting with our Step Function&lt;/li&gt;
&lt;li&gt;requestTemplates: The code here may look a little weird and scary. We are using &lt;a href="https://velocity.apache.org/engine/1.7/user-guide.html#velocity-template-language-vtl-an-introduction"&gt;Velocity Template Language (VTL)&lt;/a&gt; to dynamically insert the ARN of our Step Function and we also escape and include the JSON content of the incoming response in the ‘input’ field. This ensures that the Step Function correctly receives our payload&lt;/li&gt;
&lt;li&gt;integrationResponses: This defines how the integration handles the different HTTP response status codes. For the 200 status code, we specify that the response body should be taken from the output field in the JSON response&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Adding the new POST method is relatively straightforward, and we can do this in a few lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiGatewayStack.restAPI.root.addMethod('POST', integration, {
  methodResponses: [
    { statusCode: '200' },
    { statusCode: '400' },
    { statusCode: '500' },
  ],
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We access the root of our API and use the &lt;code&gt;addMethod&lt;/code&gt; method to create a new POST request endpoint at the root of the API. We pass the integration we created to ensure that the configuration is used. An array of &lt;code&gt;methodResponses&lt;/code&gt; is also specified, telling the API what responses we should expect from this endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Go Forth and Deploy!
&lt;/h2&gt;

&lt;p&gt;Everything is now in place for us to be able to deploy and have a working API, a new Dynamo DB table, two new Lambda Functions and an Express step function! Feel free to explore the AWS console to see all the newly created resources.&lt;/p&gt;

&lt;p&gt;You should be able to also give your sparkly new resources a test. You can test using your preferred method (e.g. in the AWS console, using an app like Postman) with a payload as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "sugar": true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Aaaaand relax
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--67qWZtp2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e0skygvb75ae7mu9iabg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--67qWZtp2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e0skygvb75ae7mu9iabg.png" alt="Relax, but don’t litter!" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re still here after covering everything we’ve covered in this episode, I tip my hat to you. We have covered a ton of stuff in this episode, so let’s have a quick recap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage first!: We created a new Dynamo DB table to store the raw payloads we receive. This gives us a great audit trail to visit if we need to debug any issues.&lt;/li&gt;
&lt;li&gt;Lambda placeholders: Two Lambda functions were created; these are just placeholders for now, but we will come back to them! These were then used within our Step Function&lt;/li&gt;
&lt;li&gt;Express Step Function: We created a custom express Step Function construct, a definition of chained steps and then used the StateMachine construct to tie it all together&lt;/li&gt;
&lt;li&gt;Stacks!: A new stack was created containing the Lambda Functions and the Express Step function needed in our app&lt;/li&gt;
&lt;li&gt;API Gateway updates: Updates were made to our API to ensure it had permission to invoke the Step Function using the StartSyncExecution. This was done by creating a new IAM role and an inline IAM policy.&lt;/li&gt;
&lt;li&gt;Invoke!: Finally, we ran through how to invoke the Step Function by sending requests to our API Gateway through the AWS console or Postman.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think we have all earned ourselves a break after consuming so much knowledge and having so much fun with CDK in this episode. Go take a well-earned break and come back for the next episode, where we’ll be dealing with those placeholder Lambda Functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;If you want to peek at the code and don’t want to read my ramblings, navigate to &lt;a href="https://github.com/TheLeePriest/lets-cdk-energy-drink-selector"&gt;this Github repo&lt;/a&gt; and spy on everything we’ll be creating in the series.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>tutorial</category>
      <category>typescript</category>
      <category>stepfunctions</category>
    </item>
    <item>
      <title>The Energy Drink Episodes 2: The Rise of the Amazon API Gateway</title>
      <dc:creator>Lee Priest</dc:creator>
      <pubDate>Tue, 14 Nov 2023 08:45:11 +0000</pubDate>
      <link>https://dev.to/aws-builders/the-energy-drink-episodes-2-the-rise-of-the-amazon-api-gateway-36ea</link>
      <guid>https://dev.to/aws-builders/the-energy-drink-episodes-2-the-rise-of-the-amazon-api-gateway-36ea</guid>
      <description>&lt;p&gt;This post is the second part of a ‘Let’s CDK’ series. &lt;a href="https://dev.to/aws-builders/lets-cdk-the-energy-drink-episodes-4a4f"&gt;You can catch up on part 1 if you haven’t already here&lt;/a&gt;. This post is part of a series that will introduce you to the AWS Cloud Development Kit (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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where were we?
&lt;/h2&gt;

&lt;p&gt;In our last episode, we covered the basics of AWS CDK and key concepts like constructs, stacks and the App construct. We also ran through how to get a CDK app setup using typescript as our choice of language. Using the synth and deploy commands, we were also able to get our new CDK app deployed to our AWS account. Feel free to have a read-through of &lt;a href="https://dev.to/aws-builders/lets-cdk-the-energy-drink-episodes-4a4f"&gt;the previous episode&lt;/a&gt; if you need any refresher before you continue.&lt;/p&gt;

&lt;h2&gt;
  
  
  What next?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MhkQ50NZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofmvwm0femw6lmtnxcf0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MhkQ50NZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ofmvwm0femw6lmtnxcf0.png" alt="This is what DALL-E thinks is next…" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, we have the basics of our app setup and deployed to our AWS account. But at the moment, we have some empty stacks with nothing really going on. While it’s great to see stacks we have created and successfully deployed to our AWS account, I’m sure we can do something more exciting.&lt;/p&gt;

&lt;p&gt;Let’s have a think about what we’re actually trying to achieve with this app that we’re building. A good way to start the transfer from the brain to a working app is to build what’s called a ‘Logical flow’ diagram. &lt;a href="https://sbrisals.medium.com/"&gt;Sheen Brisals&lt;/a&gt; has a great series of blog posts on ‘&lt;a href="https://sbrisals.medium.com/the-significance-of-solution-design-in-serverless-developments-part-i-58e0ef9dd24"&gt;The Significance of Solution Design in Serverless Developments&lt;/a&gt;’, which I wholeheartedly recommend reading. Solution designs are definitely something that should be part of your development flow when working outside of a tutorial context, as they are invaluable to not just you but your team as a whole.&lt;/p&gt;

&lt;p&gt;We’re not going to create a full solution design as part of this series, as we could likely have an entire series dedicated to it. However, we will employ a couple of key elements from the solution design process. Creating a logical flow diagram will give us something to refer back to during the build process to keep on track with the solution we are implementing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logical Flow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fSfnvIks--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hjnwoe41i4u44wbol2i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fSfnvIks--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hjnwoe41i4u44wbol2i.png" alt="The logical flow we want our app to follow" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above, you can see a basic diagram outlining the logical flow we want our application to have. A logical flow helps us think about what we want our app to do and what resources we could use to help us achieve it.&lt;/p&gt;

&lt;p&gt;Let’s first start with the ‘Receive request’ step. We won’t start with the ‘User sends request step’ as we won’t be building our user. Chat GPT can’t build humans…yet. Various services could be used when thinking about the possible AWS resources we could use to handle incoming user requests. However, we don’t just want a service that the incoming request can invoke; we also want something that will enable us to follow our logical flow.&lt;/p&gt;

&lt;p&gt;This is where we turn to the tried and true &lt;a href="https://aws.amazon.com/api-gateway/"&gt;Amazon API Gateway&lt;/a&gt; and its many integrations. Using API Gateway, we can use services like AWS Lambda or AWS Step Functions to run logic against the payload that we receive. We can also use these integrations to return responses back to the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Gateway
&lt;/h2&gt;

&lt;p&gt;If you’re unfamiliar with API Gateway or want a refresher on what it is and how it works, I recommend &lt;a href="https://aws.amazon.com/api-gateway/"&gt;reading about it here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RESTful vs. WEBSOCKET API&lt;/strong&gt;&lt;br&gt;
As we don’t need to worry about real-time two-way communication like in a chat app or similar, we will build a REST API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Access Control&lt;/strong&gt;&lt;br&gt;
As we’re not building a public API, we want to ensure we have at least some access control setup. We could go down a few different avenues when &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-to-api.html"&gt;considering access control with our API Gateway REST API&lt;/a&gt;. For our app, we are going to use a combination of an API Key, usage plan and IAM roles and policies to ensure that we are the only ones that can access our API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Gateway and CDK&lt;/strong&gt;&lt;br&gt;
Before we dive in and get our hands dirty writing some cool code to generate our API via infrastructure as code, I recommend having at least a quick glance over the &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway-readme.html"&gt;CDK documentation for the API Gateway construct library&lt;/a&gt;. I will, of course, guide you through what we are building, but it’s always good to read the documentation!&lt;/p&gt;
&lt;h2&gt;
  
  
  Enough talk, let’s build!
&lt;/h2&gt;

&lt;p&gt;At the moment, we have the basic shell of a CDK app. Now we can get down and dirty with some code and add an API Gateway REST API. We’re going to approach this by first building our own API Gateway L3 construct. Feel free to refer back to this post for a refresher on constructs if you want.&lt;/p&gt;

&lt;p&gt;Let’s first add a new &lt;code&gt;constructs&lt;/code&gt; directory at the root of the project. We’ll add all our custom constructs here. We will also organise things by having a directory for each construct in reference to the AWS service they are for. As we’re going to be creating an API Gateway construct, go ahead and add an &lt;code&gt;APIGateway&lt;/code&gt; directory inside the &lt;code&gt;constructs&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;So now your project structure should look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VpI5D4dQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ikbi6gebl91bkq1tv2va.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VpI5D4dQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ikbi6gebl91bkq1tv2va.png" alt="Our Root -&amp;gt; constructs -&amp;gt; APIGateway directory structure" width="387" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating our Construct
&lt;/h2&gt;

&lt;p&gt;Now, an empty directory won’t create an API for us. So, let’s go ahead and add an APIGateway.ts file to our APIGateway directory. We will need to import a few things to create our REST API. At the top of your APIGateway.ts file, add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { ApiKey, RestApi, UsagePlan } from 'aws-cdk-lib/aws-apigateway';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s take a quick look at what we have just imported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; This is a root construct that represents a single CloudFormation stack. Remember, we need to scope our construct to a Stack, so this will be needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Construct:&lt;/strong&gt; We are going to be creating our own APIGateway Construct so we will be extending the core Construct class.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ApiKey:&lt;/strong&gt; This is needed so we can generate an API Key&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RestApi:&lt;/strong&gt; The class that represents a REST API in API Gateway. This is what we’ll use to create our API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UsagePlan:&lt;/strong&gt; This will work with the API key to specify who can use the API and how much they can call it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we have our imports sorted, let’s create the shell of our custom &lt;code&gt;APIGateway&lt;/code&gt; construct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class APIGateway extends Construct {
    constructor(scope: Stack, id: string, props: APIGatewayProps) {
        super(scope, id);

        // This is where we're gonna have some fun!        

    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the bare bones of our &lt;code&gt;APIGateway&lt;/code&gt; Construct. You can see we’re extending the &lt;code&gt;Construct&lt;/code&gt; class and initialising it with the constructor. Three arguments are also passed into the constructor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;scope:&lt;/strong&gt; This is the scope the &lt;code&gt;Construct&lt;/code&gt; is assigned to. In our case, it will be the &lt;code&gt;Stack&lt;/code&gt; it sits within.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;id:&lt;/strong&gt; A string that represents a logical ID for the &lt;code&gt;Construct&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;props:&lt;/strong&gt; An object with any useful properties that can help us define our new &lt;code&gt;Construct&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The keen-eyed among you will have also noticed the props being typed as APIGatewayProps. We can go ahead and create the type as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type ApiGatewayProps = {
    serviceName: string;
    stage: string;
    rateLimit?: number;
    burstLimit?: number;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Passing the &lt;code&gt;serviceName&lt;/code&gt; and &lt;code&gt;stage&lt;/code&gt; down as part of the props object allows the &lt;code&gt;Construct&lt;/code&gt; to be more easily used across different stacks we may have. We can also use the &lt;code&gt;stage&lt;/code&gt; variable to differentiate across deployment environments. Setting the &lt;code&gt;rateLimit&lt;/code&gt; and &lt;code&gt;burstLimit&lt;/code&gt; as optional allows us to specify defaults inside the &lt;code&gt;Construct&lt;/code&gt; but also override if needed by a particular stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the API
&lt;/h2&gt;

&lt;p&gt;Let’s start adding the main logic of our custom &lt;code&gt;Construct&lt;/code&gt; by destructuring variables from our props object and initialising the RestApi class to create our API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class APIGateway extends Construct {
    public readonly restAPI: RestApi;

    constructor(scope: Stack, id: string, props: ApiGatewayProps) {
        super(scope, id);

        const {
            serviceName,
            stage,
            rateLimit = 100000,
            burstLimit = 1000
        } = props;

        this.restAPI = new RestApi(this, `${serviceName}-restAPI-${stage}`, {
            deployOptions: {
                stageName: stage
            },
            defaultMethodOptions: {
                apiKeyRequired: true
            }
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above is actually all you really need to create a REST API using AWS CDK. However, we don’t have any methods attached to the API, so we would run into an issue when deploying. Fear not! We will rectify this soon. Above, we destructured our variables from the props object and set the defaults for the &lt;code&gt;rateLimit&lt;/code&gt; and &lt;code&gt;burstLimit&lt;/code&gt; properties. Then, we initialised the RestApi class.&lt;/p&gt;

&lt;p&gt;We have passed &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.RestApi.html"&gt;three arguments to the RestApi class&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The scope for the RestAPI&lt;/li&gt;
&lt;li&gt;A logical ID&lt;/li&gt;
&lt;li&gt;A props object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We use the &lt;code&gt;serviceName&lt;/code&gt; and &lt;code&gt;stage&lt;/code&gt; variables to create the logical ID for the RestApi. Within the props object, we specify two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;deployOptions:&lt;/strong&gt; Settings for the API Gateway stage that link to the latest deployment when activated. We set the &lt;code&gt;stageName&lt;/code&gt; using the &lt;code&gt;stage&lt;/code&gt; variable so we can easily see what environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;defaultMethodOptions:&lt;/strong&gt; Method options to use for all methods created within this API. We specify that &lt;code&gt;apiKeyRequired&lt;/code&gt; is true. This means all methods created in this API will require an API key to be present in the request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also specify a &lt;code&gt;public readonly&lt;/code&gt; property on the construct and have this equal to the API. We do this to easily access the API outside of the construct and add methods to the API when needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating our API Key
&lt;/h2&gt;

&lt;p&gt;So, we’ve got our API setup and have specified that all methods in that API must have an API key present in the request. We should probably create an API key, so we’re able to actually use the API. Luckily, this is nice and easy within CDK world:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const apiKey = new ApiKey(this, `${serviceName}-apiKey-${stage}`, {
  apiKeyName: `${serviceName}-apiKey-${stage}`,
  generateDistinctId: true,
  stages: [this.restAPI.deploymentStage],
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the ApiKey construct we imported earlier. We can pass in the scope, logical ID, and props object to create an API key. Looking at the props object we passed to the ApiKey construct, we can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;apiKeyName:&lt;/strong&gt; A string that is set as the name for the API Key&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;generateDistinctId:&lt;/strong&gt; A boolean value that, when set to true, ensures that the name of the API key is different to the API key name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;stages:&lt;/strong&gt; An array of stages that the API key is associated with. We set this to the &lt;code&gt;deploymentStage&lt;/code&gt; of the API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We now have our API key! Woohoo!&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating our Usage Plan
&lt;/h2&gt;

&lt;p&gt;API? Check. API Key? Check. We can call it a day now, right? Not so fast! We still need to create our usage plan. If you aren’t familiar with usage plans, &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-usage-plans.html"&gt;I recommend having a read over the documentation&lt;/a&gt;. As mentioned above, our usage plan will allow us to control and monitor access to our API. We can make use of our rateLimit and burstLimit variables we saw earlier and also link API stages to it.&lt;/p&gt;

&lt;p&gt;To create our usage plan, we can do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const usagePlan = new UsagePlan(this, `${serviceName}-usagePlan-${stage}`, {
    name: `${serviceName}-${stage}`,
    throttle: {
        rateLimit,
        burstLimit
    },
    apiStages: [{
        stage: this.restAPI.deploymentStage
    }]
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the UsagePlan construct we imported, we can pass the scope, logical ID and props object (are you noticing a pattern yet?). Within the props object, we specify the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name:&lt;/strong&gt; The name given to our usage plan. Using the variables passed via the props object. We can ensure these are dynamic and related to the correct scope.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;throttle:&lt;/strong&gt; The rate limit and burst limit we want to set to ensure traffic to the API doesn’t hit a limit we don’t want. &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html"&gt;You can read more here on API request throttling&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Don’t forget!
&lt;/h2&gt;

&lt;p&gt;We have our API key and usage plan, but we need to ensure that we add the API key to the usage plan. If we don’t, we’ll have these two resources floating around in our account, with the API key just acting as an identifier without any benefit of the usage plan. Luckily, this is incredibly easy to do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;usagePlan.addApiKey(apiKey);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Here’s One I Made Earlier
&lt;/h2&gt;

&lt;p&gt;Bringing all the pieces we create above together, we should have a custom APIGateway construct that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { ApiKey, RestApi, UsagePlan } from 'aws-cdk-lib/aws-apigateway';

type ApiGatewayProps = {
    serviceName: string;
    stage: string;
    rateLimit?: number;
    burstLimit?: number;
}

export class APIGateway extends Construct {
    public readonly restAPI: RestApi;

    constructor(scope: Stack, id: string, props: ApiGatewayProps) {
        super(scope, id);

        const {
            serviceName,
            stage,
            rateLimit = 100000,
            burstLimit = 1000
        } = props;

        this.restAPI = new RestApi(this, `${serviceName}-restAPI-${stage}`, {
            deployOptions: {
                stageName: stage
            },
            defaultMethodOptions: {
                apiKeyRequired: true
            }
        });

        const apiKey = new ApiKey(this, `${serviceName}-apiKey-${stage}`, {
            apiKeyName: `${serviceName}-apiKey-${stage}`,
            generateDistinctId: true,
            stages: [this.restAPI.deploymentStage],
        });

        const usagePlan = new UsagePlan(this, `${serviceName}-usagePlan-${stage}`, {
            name: `${serviceName}-${stage}`,
            throttle: {
                rateLimit,
                burstLimit
            },
            apiStages: [{
                stage: this.restAPI.deploymentStage
            }]
        });

        usagePlan.addApiKey(apiKey);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Let’s get Stacking
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XCQQ9ZG7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2yavb1rtoaj9tsvx58ee.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XCQQ9ZG7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2yavb1rtoaj9tsvx58ee.png" alt="Let's Get Stacking!" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have our own custom &lt;code&gt;APIGateway&lt;/code&gt; construct. We can use it in our stacks. If you had a browse around the app that was created by running the &lt;code&gt;cdk init&lt;/code&gt; command we ran in the previous episode, you would have seen the &lt;code&gt;EnergyDrinkSelectorStack&lt;/code&gt; within the &lt;code&gt;energy-drink-selector.ts&lt;/code&gt; file in the lib directory. This stack gets imported into the App within the &lt;code&gt;energy-drink-selector.ts&lt;/code&gt; file in the &lt;code&gt;bin&lt;/code&gt; directory. Then, when a deployment is run, it all gets magically transformed into a Cloudformation and then turned into the AWS resources we defined.&lt;/p&gt;

&lt;p&gt;The approach we are going to use in this series is to use CDK nested stacks. “What are nested stacks?!” I hear you cry. Well, the clue is partially in the name. A nested stack is basically a child stack of a parent stack. So we can have stacks within stacks. Don’t worry. It sounds more confusing than it is in practice. For us, the &lt;code&gt;EnergyDrinkSelectorStack&lt;/code&gt; will be our parent stack, and within this stack, we will define our child stacks. &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-nested-stacks.html"&gt;You can read more about nested stacks here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an APIGatewayStack
&lt;/h2&gt;

&lt;p&gt;Earlier, we created a new &lt;code&gt;constructs&lt;/code&gt; directory for our custom constructs. Let’s do the same for our stacks. We can go ahead and create a &lt;code&gt;stacks&lt;/code&gt; directory in the root of the project. Within this new directory, we can create an &lt;code&gt;APIGatewayStack.ts&lt;/code&gt; file to house the code for our API Gateway stack.&lt;/p&gt;

&lt;p&gt;Let’s start our stack creation by handling our imports first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { NestedStack, NestedStackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import { APIGateway } from "../constructs/APIGateway/APIGateway";
import { RestApi } from "aws-cdk-lib/aws-apigateway";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s take a quick look at these imports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NestedStack:&lt;/strong&gt; The CDK construct we use to create a nested stack&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NestedStackProps:&lt;/strong&gt; A type interface for the initialisation props for the NestedStack&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Construct:&lt;/strong&gt; The scope of the NestedStack will be a Construct, as Stacks are Constructs, and we will be scoping this stack to our main EnergyDrinkSelectorStack&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APIGateway:&lt;/strong&gt; This is the custom APIGateway construct we created&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RestApi:&lt;/strong&gt; We will be using this to ensure type safety with the public readonly property we will add to our stack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ve got our imports sorted. Let’s create the actual stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export class APIGatewayStack extends NestedStack {
    public readonly restAPI: RestApi;

    constructor(scope: Construct, id: string, props?: NestedStackProps) {
        super(scope, id, props);

        const apiGateway = new APIGateway(this, 'EnergyDrinkSelectorAPI', {
            serviceName: 'energy-drink-selector',
            stage: 'dev',
        });

        this.restAPI = apiGateway.restAPI;
    }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the code above, we can see that we have used our custom APIGateway construct and passed in stack-specific values for the props. We can also see that we’re setting the public property equal to the &lt;code&gt;restAPI&lt;/code&gt; we create in the construct, allowing us to add methods where needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Last Step…I Promise
&lt;/h2&gt;

&lt;p&gt;We have our custom APIGateway construct and our custom APIGatewayStack, so what’s left? Well, we need to make sure that we are making use of these within our main &lt;code&gt;EnergyDrinkSelectorStack&lt;/code&gt; as that’s the one that is passed to the App that’s then used to synthesise the Cloudformation template used to create the AWS resources.&lt;/p&gt;

&lt;p&gt;In our &lt;code&gt;energy-drink-selector-stack.ts&lt;/code&gt; in the lib directory, all we need to do is import our APIGatewayStack and add a method to the API for CDK to allow us to deploy. We can do this as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { APIGatewayStack } from '../stacks/APIGatewayStack';

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

    const apiGatewayStack = new APIGatewayStack(this, 'EnergyDrinkSelectorAPIGatewayStack');
    apiGatewayStack.restAPI.root.addMethod('GET');
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, you can see that we import our custom &lt;code&gt;APIGatewayStack&lt;/code&gt;, initialise it and store it in an &lt;code&gt;apiGatewayStack&lt;/code&gt; variable. We then add a GET method to the API to satisfy the deployment requirement of having at least one method on the API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Go Forth and Deploy!
&lt;/h2&gt;

&lt;p&gt;With all the pieces of the puzzle now in place to create our very own REST API in API Gateway via CDK, we can run &lt;code&gt;cdk deploy&lt;/code&gt;, and as if by magic, we should have a brand new shiny API waiting for us in the AWS console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M0i7OJqE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9h5nt6ldxa9gc0g0eoya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M0i7OJqE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9h5nt6ldxa9gc0g0eoya.png" alt="Our brand new shiny API in the AWS console!" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Aaaaand relax
&lt;/h2&gt;

&lt;p&gt;We covered quite a lot in this episode. Kudos for sticking with it and making it through! Let’s have a quick recap of what we covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Logical Flow diagram:&lt;/strong&gt; We took some inspiration from the realm of the solution design and created a logical flow diagram to help us focus on what we wanted to achieve&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway:&lt;/strong&gt; We looked at some points around API Gateway in relation to the app we’ll be building. We decided on a RESTful API over a WEBSOCKET API as we don’t need the two-way communication functionality that WEBSOCKET APIs offer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access control:&lt;/strong&gt; We covered things like API Keys and Usage Plans to ensure that we can both lock down and limit API usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Construct:&lt;/strong&gt; We created our own custom construct! An L3 construct that allows us to create a REST API in API Gateway&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nested stacks:&lt;/strong&gt; We created a stack using the NestedStack construct, allowing us to have child stacks within a parent stack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With all this newly acquired knowledge swirling around in your brain, I’d recommend having another look over the code and familiarising yourself with the syntax and patterns used, as we’ll be seeing similar patterns in the upcoming episodes.&lt;/p&gt;

&lt;p&gt;I think you’ve earned a rest after all this fun! Go grab a beverage and a snack, and then start preparing for our next episode, which will focus on a little service called Step Functions.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;If you want to peek at the code and don’t want to read my ramblings, navigate to &lt;a href="https://github.com/TheLeePriest/lets-cdk-energy-drink-selector"&gt;this Github repo&lt;/a&gt; and spy on everything we’ll be creating in the series.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>apigateway</category>
      <category>tutorial</category>
      <category>aws</category>
    </item>
    <item>
      <title>Let’s CDK: The Energy Drink Episodes</title>
      <dc:creator>Lee Priest</dc:creator>
      <pubDate>Mon, 06 Nov 2023 10:12:00 +0000</pubDate>
      <link>https://dev.to/aws-builders/lets-cdk-the-energy-drink-episodes-4a4f</link>
      <guid>https://dev.to/aws-builders/lets-cdk-the-energy-drink-episodes-4a4f</guid>
      <description>&lt;p&gt;Ever since I started my foray into the world of Serverless, I have mainly worked with &lt;a href="https://www.serverless.com/"&gt;Serverless Framework&lt;/a&gt; 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.&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS CD...What?
&lt;/h2&gt;

&lt;p&gt;Rather than writing my own description of what AWS CDK is, I will borrow from &lt;a href="https://aws.amazon.com/cdk/faqs/"&gt;AWS’ FAQ page&lt;/a&gt; to explain:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;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 &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/"&gt;documentation for CDK here&lt;/a&gt;. It is worth looking at, even if you only glance over it to see how much it provides.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Constructs = Building blocks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PNKsIZvZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/evz91vsjede7so9pozdd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PNKsIZvZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/evz91vsjede7so9pozdd.png" alt="LEGO® set T. rex Breakout — Source: LEGO.com" width="800" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although it’s a scary-sounding word, &lt;a href="https://docs.aws.amazon.com/prescriptive-guidance/latest/best-practices-cdk-typescript-iac/constructs-best-practices.html"&gt;constructs in CDK are the basic building blocks of an AWS CDK application&lt;/a&gt;. To continue with our LEGO likeness, let’s imagine that we have the awesome &lt;a href="https://www.lego.com/en-gb/product/t-rex-breakout-76956"&gt;T. rex Breakout&lt;/a&gt; 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.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A CDK Construct is basically our pre-made T. Rex enclosure plinth&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Construct types&lt;/strong&gt;&lt;br&gt;
Another scary-sounding idea, I know, but fear not! Constructs in CDK are split into three different types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;L1 Constructs:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Official definition&lt;/em&gt;: An L1 construct is the exact resource CloudFormation defines. Using a Cfn prefix, these constructs are basic and must be manually configured.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Our LEGO analogy explanation&lt;/em&gt;: 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.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;L2 Constructs:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Official definition&lt;/em&gt;: An L2 construct has common boilerplate code and logic. They come with default configurations and commonly combine corresponding L1 constructs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Our LEGO analogy explanation&lt;/em&gt;: 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.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;L3 Constructs:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Official definition&lt;/em&gt;: 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.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Our LEGO analogy explanation&lt;/em&gt;: 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.&lt;/p&gt;
&lt;h2&gt;
  
  
  Piecing it together
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YjpJ9xGQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzef5cv8wwih48tsocr5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YjpJ9xGQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzef5cv8wwih48tsocr5.jpeg" alt="Photo by Charles Snow on Unsplash" width="720" height="405"&gt;&lt;/a&gt;&lt;br&gt;
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’.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A stack is a unit of deployment and has resources defined within its scope, either directly or indirectly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A stack of building blocks that together form a part of your application&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;We need a box to put it all in&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/apps.html"&gt;serves as each stack’s scope&lt;/a&gt;. 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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code example above, you can see that we create a new app and then &lt;a href="https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.App.html"&gt;define the construct where the app is used as the parent scope&lt;/a&gt;. 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:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;cdk synth&lt;/code&gt; — This command executes your app, which causes the resources defined within it to be transformed into a CloudFormation template. A YAML-format template is&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cdk deploy&lt;/code&gt; — 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.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What’s this got to do with energy drinks?
&lt;/h2&gt;

&lt;p&gt;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 &lt;a href="https://medium.com/lego-engineering/energise-yourself-with-express-step-functions-6e01b8d86847"&gt;my previous post here&lt;/a&gt; and built it using CDK.&lt;/p&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt;&lt;br&gt;
An application that helps the user choose which energy drink they should drink.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it needs to do:&lt;/strong&gt;&lt;br&gt;
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.&lt;/p&gt;
&lt;h2&gt;
  
  
  Before we get started
&lt;/h2&gt;

&lt;p&gt;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 &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html"&gt;getting started with CDK&lt;/a&gt;, AWS have a great one &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/hello_world.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;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:&lt;/p&gt;

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

&lt;p&gt;If you are using VS Code, the &lt;a href="https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/aws-cdk-apps.html"&gt;AWS toolkit for VS Code&lt;/a&gt; is helpful when working with CDK and AWS.&lt;/p&gt;
&lt;h2&gt;
  
  
  Let’s get started!
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir energy-drink-selector
cd energy-drink-selector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now we’re in the &lt;code&gt;energy-drink-selector&lt;/code&gt; 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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk init app --language typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this command in our &lt;code&gt;energy-drink-selector&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i esbuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we now have a basic CDK application, we can deploy it to our AWS account. Let’s first synthesize the app by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk synth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a YAML-format CloudFormation template and an output of our app in a &lt;code&gt;cdk.out&lt;/code&gt; directory. We can then deploy our application to our AWS account using the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aaaaand relax
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AVgXcpjx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/37vyw4wrvk7nq1e74frf.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AVgXcpjx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/37vyw4wrvk7nq1e74frf.jpeg" alt="Photo by Clem Onojeghuo on Unsplash" width="720" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is CDK — Amazon Cloud Development Kit — An open-source framework for defining cloud infrastructure as code and deploying it through AWS CloudFormation&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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).&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
      <category>tutorial</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
