Learn
M4: Backend

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

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:

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 and DB_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 with i-)
    • DB_ENDPOINT: RDS > DB Instances > Select the regional cluster with a DB Identifier like <appId>-<stageName>-data-... > Endpoints > Write instance endpoint (ends with rds.amazonaws.com)
  • 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>.
  • 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
  • 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 use core/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 variable DB_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:
album-summary-handler.ts
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 at infra/src/app/stateless/job-stack.ts. Ensure it extends Stack.
  • Use this pattern (opens in a new tab) from Serverless Land as a starting point.
  • Utilize gboost-infra's Function 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 and connectFnToDb utility functions like in infra/src/app/stateless/ui-stack.ts.
  • Instantiate the stack within infra/src/app-stage.ts.
  • Deploy the new JobStack with cdk 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>")

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