In the first article in this two-part series, we leveled-up on AWS CDK fundamentals and built a CDK Stack that deploys a basic API Gateway + Lambda + DynamoDB API to receive orders from a (fake) ecommerce website. We deployed our code with the CDK CLI, made a call to our
POST /checkout API endpoint and then… it broke.
In this article, we’re going to fix the API! We’ll also cover how two popular code management utilities, Lerna and Webpack, can be used to better manage the AWS CDK code used to deploy your back-end services. We’ll start where we left off in the first article and refactor the code in a few steps.
Better Code Organization With Lerna
While we’re certainly not working with a large codebase in our Reactshoppe API example, I’d still like to package the code up in a more meaningful way while working towards fixing our show-stopping bug.
We’ll do this in three steps:
- Install Lerna
- Move some files around
- Update references
Step 1 - Install Lerna
npx lerna init in our root project directory. Once done, you’ll see an empty “packages” directory and a lerna.json file. Next, we’re going to run
npx lerna create [package name] --private for each of the following packages we want to create:
- reactshoppe-database - the CDK Construct that creates our DynamoDB Order table
- reactshoppe-api - the CDK Construct that creates our API Gateway and binds API endpoints to our Lambda functions
- functions - the Lambda functions that handle API requests
- stack - The CDK Stack that deploys the database, API Gateway, and Lambda functions
lerna create command adds a little more cruft than I’d like for this example, so I’ve removed the
lib directories and everything below the
"main" field in the
package.json file for each package. You can see the changes from installing Lerna and creating our four packages here.
Step 2 - Move Some Files Around
Let’s move the DynamoDB Construct, API Gateway Construct, AWS Lambda source code, and Stack definitions out of
./lib and into their requisite package directories. There’s not much to this, but feel free to check out the results in this commit.
Our updated project structure looks like this:
Step 3 - Update References
Almost there! We need to update dependencies between packages to use the local Lerna-managed packages and update our code to reference package names rather than file paths.
Start by updating dependencies between packages. We’ve got a dependency in
reactshoppe-database and a pair of dependencies in
reactshoppe-database. We can create these dependencies by invoking a few
lerna add commands:
npx lerna add reactshoppe-database --scope=functions
npx lerna add reactshoppe-api --scope=stack
npx lerna add reactshoppe-database --scope=stack
Lerna creates the appropriate symlinks in each packages’ respective
node_modules directory and updates each
package.json file. From now on, when we run
npx lerna bootstrap, the dependencies between local packages will be linked. We can also update the references to these packages in our code to use the package name, without having to spell out the relative file path. Check out this commit to see the differences after package dependencies have been added via Lerna and this one for the requisite changes to references in the code.
npx cdk deploy command will follow the symlinks created by Lerna when creating the Lambda deployment package that is uploaded to AWS. This ensures that all code is available to our Lambda function at runtime.
Now our bug is fixed! The reactshoppe-database module is available at runtime when the
POST /checkout request is handled by our Lambda function. Further, our code is now nicely organized into packages that encapsulate the components of our API. But there’s still a little more optimization we can do...
After adding the following
webpack.config.js file to
...we’ll update our npm scripts in
package.json to include Webpack in the build process:
And finally we’ll update the reactshoppe-api Construct to point to the “entrypoint” file created by our Webpack configuration:
The AWS CDK + Lerna + Webpack combined gives you a powerful set of tools to cleanly manage infrastructure and application logic. As we’ve seen here, this combo provides a particularly elegant approach to building serverless APIs hosted on AWS. Keep this in mind the next time you need to bang out a service for a proof of concept; you can work quickly while also building a solid foundation to scale your POC if it takes off.