---
title: "Holiday Shopping"
layout: challenge/single
description: |
Create a simple shopping list app using AWS Fargate and MongoDB Atlas
meta_desc: |
Create a simple shopping list app using AWS Fargate and MongoDB Atlas
meta_image: /images/challenge/challenge-dec-meta.png
banner_image: /images/challenge/challenge-dec-banner.png
---
Holiday Shopping Challenge!
## What you will learn
The holidays are upon us and mere anarchy has been loosed upon our psyches. More specifically how do you keep track of everything you need to buy for gifts or food?!? Surely some salvation is at hand? Lucky for you, our friend, The Pulumipus, has created a simple to-do list application to bring order to your life. In this challenge, you will build this simple to-do list application that has a React frontend, Express backend, and a MongoDB database. This frontend and backend of the app run in Fargate with an Application Load Balancer (ALB) in front and the database is running in a MongoDB Atlas cluster.

After completing this challenge and if you feel so inclined to thank The Pulumipus, please write a blog post or post a quick video about it. Tag us on social media or email us at [da@pulumi.com](mailto:da@pulumi.com), and we will help spread the word about your experience.
## Prerequisites
In order to complete this challenge, you'll need a couple things set up in advance. The challenge utilizes the MongoDB Cloud free tier and incurs a small charge for using AWS Fargate.
- A [Pulumi account](https://app.pulumi.com/signup)
- The [Pulumi CLI](/docs/install/)
- [Python 3.9 or higher](https://www.python.org/downloads/)
- [Docker](https://docs.docker.com/get-docker/)
- An [AWS account](https://portal.aws.amazon.com/)
- The [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
- A [MongoDB Cloud account](https://www.mongodb.com/cloud/atlas/register)
- A [GitHub account](https://github.com/signup)
## Challenge
### Step 1. Initialize a project
You will first clone the base application and then the rest of the steps will take you through building the Pulumi program.
```shell
git clone -b challenge https://github.com/aaronkao/atlas-fargate.git
```
Next, initialize the stack.
```shell
cd atlas-fargate
pulumi stack init dev
```
You will also need to export your AWS and MongoDB Cloud credentials. To access your MongoDB Cloud credentials, go to the __Organization Access Manager__ panel and the __API Keys__ tab. If you don't have any API keys, please click Create API Key and select _Organization Project Creator_ under Organization Permissions.
```shell
export AWS_ACCESS_KEY_ID=
export AWS_SECRET_ACCESS_KEY=
export MONGODB_ATLAS_PUBLIC_KEY=
export MONGODB_ATLAS_PRIVATE_KEY=
```
Lastly, you will need to set your AWS region (e.g., us-west-2) in your Pulumi configuration.
```shell
pulumi config set aws:region
```
### Step 2. Provision containers on AWS Fargate
Let's start by building and publishing our application from /app/frontend and /app/backend as container images to an ECR repository. The frontend app is a static website served by an nginx server. The backend app is an Express server that retrieves and stores data in a MongoDB database. Add the below into `__main__.py`.
```python
# An ECR repository to store our application's container images
repo = awsx.ecr.Repository("grocery_list_repo")
frontend_image = awsx.ecr.Image(
"grocery_frontend_image",
repository_url=repo.url,
path="./app/frontend")
# Build and publish our application from /app/frontend and /app/backend
# as container images to the ECR repository
backend_image = awsx.ecr.Image(
"grocery_backend_image",
repository_url=repo.url,
path="./app/backend")
```
Next, let's create an Application Load Balancer (ALB) to receive traffic and an [Amazon Elastic Container Service (ECS)](https://www.pulumi.com/learn/glossary/aws-ecs/) cluster in which the containers will run.
```python
# An ECS cluster to deploy into
cluster = aws.ecs.Cluster("cluster")
# An ALB to serve the frontend service to the internet
lb = awsx.lb.ApplicationLoadBalancer("grocery-lb")
```
Now, create an [AWS Fargate](https://www.pulumi.com/learn/glossary/aws-fargate/) service that will run the containers. There are some configuration values for the Fargate service that you can set via Pulumi config, but for this example, you can just use the default values. This code creates a Fargate service that runs a task with two containers, a front and back. The front container is using the frontend image created in Step 1 and is wired to receive traffic from the ALB. The back container is using the backend image and listens on port 8000.
```python
# AWS configs
container_port = config.get_int("containerPort", 80)
cpu = config.get_int("cpu", 1024)
memory = config.get_int("memory", 1024)
# Deploy an ECS Service on Fargate to host the application containers
service = awsx.ecs.FargateService(
"grocery-service",
cluster=cluster.arn,
assign_public_ip=True,
task_definition_args=awsx.ecs.FargateServiceTaskDefinitionArgs(
containers={
"front": awsx.ecs.TaskDefinitionContainerDefinitionArgs(
image=frontend_image.image_uri,
cpu=cpu,
memory=memory,
essential=True,
port_mappings=[awsx.ecs.TaskDefinitionPortMappingArgs(
container_port=container_port,
target_group=lb.default_target_group,
)],
),
"back": awsx.ecs.TaskDefinitionContainerDefinitionArgs(
image=backend_image.image_uri,
cpu=cpu,
memory=memory,
essential=True,
port_mappings=[awsx.ecs.TaskDefinitionPortMappingArgs(
container_port=8000,
host_port=8000
)],
),
}
),
desired_count=1
)
# AWS export
pulumi.export("app_url", Output.concat("http://", lb.load_balancer.dns_name))
```
Run `pulumi up` and select yes to perform the update (this can take up to 10 minutes). Pulumi will output the `app_url`. Go to the URL, and you will be presented with the Pulumipus' Grocery List web application. You can try to add some items, but nothing will happen because there is no database connected yet. You will do that in the next step.
### Step 3. Create a MongoDB Atlas database
The web app stores the grocery list items inside a MongoDB database. MongoDB Atlas is a fully managed cloud database that you will be using for this application. Add the below before the code from the previous steps (above the ECR repo declaration) in `__main__.py`. This code creates a MongoDB project, sets up the network access controls, creates a Free Tier cluster in `US_WEST_2` in AWS, and a database user that is scoped to the created cluster.
```python
# MongoDB Atlas configs
db_username = config.require("dbUser")
db_password = config.require_secret("dbPassword")
atlas_org_id = config.require("orgID")
# Create MongoDB Project
mongo_project = mongodb.Project("mongo_project", org_id=atlas_org_id)
# Open access to all IPs
mongo_acl = mongodb.ProjectIpAccessList("mongo_acl",
cidr_block="0.0.0.0/0",
comment="Open access for backend",
project_id=mongo_project.id,)
# Create Free Tier cluster
mongo_cluster = mongodb.Cluster("mongo-cluster",
backing_provider_name="AWS",
project_id=mongo_project.id,
provider_instance_size_name="M0",
provider_name="TENANT",
provider_region_name="US_WEST_2")
# Create Database user and give access to the cluster and database
mongo_user = mongodb.DatabaseUser("db_user",
auth_database_name="admin",
labels=[mongodb.DatabaseUserLabelArgs(
key="project",
value="pulumi",
)],
password=db_password,
project_id=mongo_project.id,
roles=[
mongodb.DatabaseUserRoleArgs(
database_name="grocery-list",
role_name="readWrite",
),
mongodb.DatabaseUserRoleArgs(
database_name="admin",
role_name="readAnyDatabase",
),
],
scopes=[
mongodb.DatabaseUserScopeArgs(
# Extracts the cluster name to add to database scopes
name=Output.all(mongo_cluster.srv_address).apply(
lambda v: re.split("\.|\/\/", v[0])[1]),
type="CLUSTER",
),
],
username=db_username
)
```
Next, you need to set the config values for your MongoDB Cloud org, database username, and database password. The Organization ID is under the __Organization Settings__ panel in the MongoDB Cloud console. The database username and password values are self-selected and don't require you to look up anything in the MongoDB Cloud console.
```shell
pulumi config set orgID [value]
pulumi config set dbUser [value]
pulumi config set dbPassword [value] --secret
```
### Step 4. Pass database URL as environment variable to backend container
Before you update the stack, you need to pass the URL of the database to the backend container so it can connect to it. Add the highlighted into the FargateService code.
```python {.line-numbers hl_lines=["26-31"]}
service = awsx.ecs.FargateService(
"grocery-service",
cluster=cluster.arn,
assign_public_ip=True,
task_definition_args=awsx.ecs.FargateServiceTaskDefinitionArgs(
containers={
"front": awsx.ecs.TaskDefinitionContainerDefinitionArgs(
image=frontend_image.image_uri,
cpu=cpu,
memory=memory,
essential=True,
port_mappings=[awsx.ecs.TaskDefinitionPortMappingArgs(
container_port=container_port,
target_group=lb.default_target_group,
)],
),
"back": awsx.ecs.TaskDefinitionContainerDefinitionArgs(
image=backend_image.image_uri,
cpu=cpu,
memory=memory,
essential=True,
port_mappings=[awsx.ecs.TaskDefinitionPortMappingArgs(
container_port=8000,
host_port=8000
)],
environment=[{
"name":"DATABASE_URL",
"value":Output.format("mongodb+srv://{0}:{1}@{2}", db_username, db_password,
Output.all(mongo_cluster.srv_address).apply(
lambda v: v[0].split("//"))[1])
}],
),
}
),
desired_count=1
)
```
### Step 5. Validate endpoints
Run `pulumi up` and select yes to update the stack. Go to the `app_url` export to validate that the endpoints of your deployed infrastructure is working. You can now add, delete, and check off items because the application is now able to connect to your newly created Atlas database.

## Congratulations
Congratulations! You've completed this Pulumi Challenge. Tag us on social media or email us at [da@pulumi.com](mailto:da@pulumi.com) and tell us what you thought of this Pulumi Challenge!
### What you have learned
In this challenge, you have learned how to build a web application as a container image and push it to Amazon Elastic Container Registry. You also learned how to deploy the containerized application on AWS Fargate with traffic load balanced through an Application Load Balancer. Lastly, you learned how to create a MongoDB Atlas cluster and database for your web application to store and retrieve data.
### Clean up
If you'd like to tear down all of these resources and delete your stack, run `pulumi destroy -rf --remove`. Otherwise, have fun playing around with your infrastructure stack and add whatever you like! 🙂