Module 4: Backend
Green Boost (GB) uses Node.js (opens in a new tab) as it's JavaScript server side runtime, Zod (opens in a new tab) for schema validation, and Drizzle (opens in a new tab) as an ORM and automatic migration generator.
Learn
- Node.js: read docs on Getting Started (opens in a new tab), Asynchronous Work (opens in a new tab), Manipulating Files (opens in a new tab), and Command Line (opens in a new tab)
- Lambda Best Practices (opens in a new tab)
- Zod: scan docs (opens in a new tab)
- Drizzle: scan Drizzle ORM docs (opens in a new tab) and Drizzle Kit docs (opens in a new tab)
Apply
M4.1 - DB Port Forwarding
The Aurora PostgreSQL GB template runs a DB instance in the AWS Cloud, but how can you connect to it when developing? There are several options, but we'll use SSM Session Manager Port Forwarding. In order to do so, follow these steps:
- You should already have the AWS CLI installed by following the prerequisites
- Install the Session Manager Plugin for the AWS CLI with the following commands from here (opens in a new tab)
curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip" -o "sessionmanager-bundle.zip"
unzip sessionmanager-bundle.zip
sudo ./sessionmanager-bundle/install -i /usr/local/sessionmanagerplugin -b /usr/local/bin/session-manager-plugin
session-manager-plugin
- In order to forward the port from our DB to our local machine, we need a bastion host (opens in a new tab). This has already been created for you in the template. Next, we'll need 2 environment variables:
DB_BASTION_ID
andDB_ENDPOINT
. All of these values are exported by the CloudFormation templates and therefore were printed to your terminal when deploying the web app so you can find the values by scanning the logs or by going to the AWS Console. Instructions to find these values in the console are below.- DB_BASTION_ID: EC2 > Instances (running) > row with
<stageName>-ssm-db-bastion
Name > Instance ID (starts withi-
) - DB_ENDPOINT: RDS > DB Instances > Select the regional cluster with a DB Identifier like
<appId>-<stageName>-data-...
> Endpoints > Write instance endpoint (ends withrds.amazonaws.com
)
- DB_BASTION_ID: EC2 > Instances (running) > row with
- Export those environment variables in your shell or persist them in your .envrc file (learn more here)
- Within
core/
folder, run:pnpm db:connect
- You should now see "Waiting for connections...". This means a port from your DB is being forwarded through your DB bastion to your local machine!
The default timeout of SSM Session Manager is 20 minutes. You may find this annoying. You can increase the timeout up to 60 minutes in the AWS Console by going to Systems Manager > Session Manager > Preferences > Edit > Idle session timeout
M4.2 - DB GUI
With port forwarding setup, you can now visualize your DB with a GUI like pgAdmin (opens in a new tab). Below are steps for setting up pgAdmin, but you're welcome to use another DB GUI of your choice.
- Install pgAdmin.
- Right click on Servers in the Object Explorer. Then select Register > Server.
- General tab:
- Name:
<appId>-<stageName>
.
- Name:
- Connection tab:
- Host name/address:
0.0.0.0
- Username:
<appId>_admin
- Password: retrieve from Secrets Manager with steps: AWS Console > Secrets Manager > Select secret with Description:
Generated by the CDK for the stack: <appId>-<stageName>-data
> Secret Value Card > click Retrieve secret value button > copy Secret value of Secret key of "password". - Save password?: yes
- Host name/address:
- Click save.
- Then drill into your DB Server to view tables:
<appId>-<stageName>
> Databases ><appId>_db
> Schemas ><appId>
> Tables. - Right click on
item
table and then select "View/Edit Data" > All Rows. - Now you can visualize your data locally as you develop.
M4.3 - Create a New Album Table
Next, we'll create a new table in our DB that will store albums supporting the feature we began working on in module 2.
- Define the album table in
core/src/modules/album/album.db.ts
following the requirements specified in module 2. You can usecore/src/modules/item/item.db.ts
to help you. - With our table defined, how do we translate this definition into SQL code to update our DB? This is where Drizzle comes in as you learned above.
- To generate the SQL to update our DB an albums table we'll run
pnpm db:generate
. But first, we need to set the environment variableDB_SECRET_ARN
. You can find this value in the AWS Console on the same screen you retrieved the secret. - Within
core/
, run:pnpm db:generate
. - Now you should see a new migration file generated within
core/src/db/drizzle/
. - Next, we'll execute the migration on our DB. Run:
pnpm db:migrate
. - Refresh the tables in your DB GUI and now you should see the
album
table!
M4.4 - Refactor CRUD Use Cases
With the album DB table ready to be used, now you'll need to refactor the use case functions you created in module 2 to use the actual DB instead of the JSONPlaceholder API. Don't worry about using the clean code architecture like the item module, you can include all related code in the <action>.usecase.ts
file. We'll refactor the use cases in module 7. Make sure to export your use case functions from core/src/modules/album/index.ts
as we'll be using these functions in the next module.
Bonus
M4.5 - Create a Daily Album Summary Notification Lambda Function
Now we've been asked to deliver daily emails to an administrator with the number of albums in the table. First, we need to create a lambda function.
- Create the file:
core/src/adapters/primary/album-summary-handler.ts
with the below template:
import { fileURLToPath } from "node:url";
export const handler = () => {
let count = 0;
// TODO: add code here to get count of rows in album table
console.log(count);
};
if (process.argv[1] === fileURLToPath(import.meta.url)) {
handler();
}
- The code at the bottom of the above snippet ensures the
handler
is only run if invoked directly. Learn more here (opens in a new tab). - As you fill in the code to summarize the notifications, test it out by running
pnpm tsx src/adapters/primary/album-summary-handler.ts
M4.6 - Create Job Stack
Now create the infrastructure required to generate the daily album summary emails. You'll need a Lambda function and EventBridge rule.
- Create a
JobStack
class atinfra/src/app/stateless/job-stack.ts
. Ensure it extendsStack
. - Use this pattern (opens in a new tab) from Serverless Land as a starting point.
- Utilize
gboost-infra
'sFunction
construct built on NodejsFunction (opens in a new tab) to automate bundling the function with esbuild (opens in a new tab). - Ensure your lambda function can access the DB by using
getDbFnProps
andconnectFnToDb
utility functions like ininfra/src/app/stateless/ui-stack.ts
. - Instantiate the stack within
infra/src/app-stage.ts
. - Deploy the new
JobStack
withcdk deploy
. - Manually trigger your rule to ensure expected output is logged.
- You can manually trigger your rule by disabling (
aws events disable-rule --name "<rule-name>"
) and then enabling (aws events enable-rule --name "<rule-name>"
)
- You can manually trigger your rule by disabling (
M4.7 - Setup Email with SES
We'll use Amazon SES to email yourself the summary email. In the future you can replace your email with the administrator's email. Follow the below steps.
- AWS Console > SES > Verified Identities.
- Create Identity with your email address.
- Verify the identity by clicking on the email verification link sent to your email.
- Now use the AWS SDK for JS V3 to send an email with the following template. Use the "Send email" example here (opens in a new tab).
- Use the template below for the
Message.Body.Text
input.
const message = `Hello,
The album table has ${count} rows.
Thank you.
`;
- Deploy the updated lambda function and then manually trigger the rule to ensure email is sent correctly.
- Optionally wait a day for the rule to automatically trigger