Skip to content

Commit b22305c

Browse files
author
Tom McCarthy
authored
chore: amplify fixes (aws-samples#10)
* chore: Correct parameter descriptions, add s3:CreateBucket permission for amplify, remove stackname parameter * fix: remove local S3 bucket creation from amplify console workflow * fix: install aws cli in build container * chore: docs update for amplify console * chore: README cleanup
1 parent 0e486e5 commit b22305c

7 files changed

+90
-25
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
.env.local
1+
.env.local
2+
.idea

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ create-bucket:
2626
@echo "Checking if S3 bucket exists s3://$(S3_BUCKET)"
2727
@aws s3api head-bucket --bucket $(S3_BUCKET) || (echo "bucket does not exist at s3://$(S3_BUCKET), creating it..." ; aws s3 mb s3://$(S3_BUCKET) --region $(REGION))
2828

29-
amplify-deploy: create-bucket
29+
amplify-deploy:
3030
aws cloudformation deploy \
3131
--template-file ./amplify-ci/amplify-template.yaml \
3232
--capabilities CAPABILITY_IAM \

README.md

+82-20
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,54 @@
11
# Serverless Shopping Cart Microservice
22

3-
This application is a sample application to demonstrate how you could implement a shopping cart microservice using serverless technologies on AWS. The backend is built as a REST API interface, making use of [Amazon API Gateway](https://aws.amazon.com/api-gateway/), [AWS Lambda](https://aws.amazon.com/lambda/), [Amazon Cognito](https://aws.amazon.com/cognito/), and [Amazon DynamoDB](https://aws.amazon.com/dynamodb/). The frontend is a Vue.js application using the [AWS Amplify](https://aws-amplify.github.io/) SDK for authentication and communication with the API.
3+
This application is a sample application to demonstrate how you could implement a shopping cart microservice using
4+
serverless technologies on AWS. The backend is built as a REST API interface, making use of [Amazon API Gateway](https://aws.amazon.com/api-gateway/), [AWS Lambda](https://aws.amazon.com/lambda/), [Amazon Cognito](https://aws.amazon.com/cognito/), and [Amazon DynamoDB](https://aws.amazon.com/dynamodb/). The frontend is a Vue.js application using the [AWS Amplify](https://aws-amplify.github.io/) SDK for authentication and communication with the API.
45

5-
To assist in demonstrating the functionality, a bare bones mock "products" service has also been included. Since the authentication parts are likely to be shared between components, there is a separate template for it. The front-end doesn't make any real payment integration at this time.
6+
To assist in demonstrating the functionality, a bare bones mock "products" service has also been included. Since the
7+
authentication parts are likely to be shared between components, there is a separate template for it. The front-end
8+
doesn't make any real payment integration at this time.
69

710
## Architecture & Design
811

9-
![Architecture Diagram](./architecture.png)
12+
![Architecture Diagram](./images/architecture.png)
1013

1114
## Design Notes
1215

1316
Before building the application, I set some requirements on how the cart should behave:
1417

15-
- Users should be able to add items to the cart without logging in (an "anonymous cart"), and that cart should persist across browser restarts etc.
16-
- When logging in, if there were products in an anonymous cart, they should be added to the user's cart from any previous logged in sessions.
18+
- Users should be able to add items to the cart without logging in (an "anonymous cart"), and that cart should persist
19+
across browser restarts etc.
20+
- When logging in, if there were products in an anonymous cart, they should be added to the user's cart from any
21+
previous logged in sessions.
1722
- When logging out, the anonymous cart should not have products in it any longer.
18-
- Items in an anonymous cart should be removed after a period of time, and items in a logged in cart should persist for a longer period.
23+
- Items in an anonymous cart should be removed after a period of time, and items in a logged in cart should persist
24+
for a longer period.
1925
- Admin users to be able to get an aggregated view of the total number of each product in users' carts at any time.
2026

2127
### Cart Migration
2228

23-
When an item is added to the cart, an item is written in DynamoDB with an identifier which matches a randomly generated (uuid) cookie which is set in the browser. This allows a user to add items to cart and come back to the page later without losing the items they have added. When the user logs in, these items will be removed, and replaced with items with a user id as the pk. If the user already had that product in their cart from a previous logged in session, the quantities would be summed. Because we don't need the deletion of old items to happen immediately as part of a synchronous workflow, we put messages onto an SQS queue, which triggers a worker function to delete the messages.
29+
When an item is added to the cart, an item is written in DynamoDB with an identifier which matches a randomly generated
30+
(uuid) cookie which is set in the browser. This allows a user to add items to cart and come back to the page later
31+
without losing the items they have added. When the user logs in, these items will be removed, and replaced with items
32+
with a user id as the pk. If the user already had that product in their cart from a previous logged in session, the
33+
quantities would be summed. Because we don't need the deletion of old items to happen immediately as part of a
34+
synchronous workflow, we put messages onto an SQS queue, which triggers a worker function to delete the messages.
2435

25-
To expire items from users' shopping carts, DynamoDB's native functionality is used where a TTL is written along with the item, after which the item should be removed. In this implementation, the TTL defaults to 1 day for anonymous carts, and 7 days for logged in carts.
36+
To expire items from users' shopping carts, DynamoDB's native functionality is used where a TTL is written along with
37+
the item, after which the item should be removed. In this implementation, the TTL defaults to 1 day for anonymous
38+
carts, and 7 days for logged in carts.
2639

2740
### Aggregated View of Products in Carts
2841

29-
It would be possible to scan our entire DynamoDB table and sum up the quantities of all the products, but this will be expensive past a certain scale. Instead, we can calculate the total as a running process, and keep track of the total amount.
42+
It would be possible to scan our entire DynamoDB table and sum up the quantities of all the products, but this will be
43+
expensive past a certain scale. Instead, we can calculate the total as a running process, and keep track of the total
44+
amount.
3045

31-
When an item is added, deleted or updated in DynamoDB, an event is put onto DynamoDB Streams, which in turn triggers a Lambda function. This function calculates the change in total quantity for each product in users' carts, and writes the quantity back to DynamoDB. The Lambda function is configured so that it will run after either 60 seconds pass, or 100 new events are on the stream. This would enable an admin user to get real time data about the popular products, which could in turn help anticipate inventory. In this implementation, the API is exposed without authentication to demonstrate the functionality.
46+
When an item is added, deleted or updated in DynamoDB, an event is put onto DynamoDB Streams, which in turn triggers a
47+
Lambda function. This function calculates the change in total quantity for each product in users' carts, and writes the
48+
quantity back to DynamoDB. The Lambda function is configured so that it will run after either 60 seconds pass, or 100
49+
new events are on the stream. This would enable an admin user to get real time data about the popular products, which
50+
could in turn help anticipate inventory. In this implementation, the API is exposed without authentication to
51+
demonstrate the functionality.
3252

3353

3454
## Api Design
@@ -44,7 +64,8 @@ POST
4464
Accepts a product id and quantity as json. Adds specified quantity of an item to cart.
4565

4666
`/cart/migrate`
47-
Called after logging in - migrates items in an anonymous user's cart to belong to their logged in user. If you already have a cart on your logged in user, your "anonymous cart" will be merged with it when you log in.
67+
Called after logging in - migrates items in an anonymous user's cart to belong to their logged in user. If you already
68+
have a cart on your logged in user, your "anonymous cart" will be merged with it when you log in.
4869

4970
`/cart/checkout`
5071
Currently just empties cart.
@@ -55,7 +76,8 @@ Accepts a product id and quantity as json. Updates quantity of given item to pro
5576

5677
GET
5778
`/cart/{product-id}/total`
58-
Returns the total amount of a given product across all carts. This API is not used by the frontend but can be manually called to test.
79+
Returns the total amount of a given product across all carts. This API is not used by the frontend but can be manually
80+
called to test.
5981

6082
### Product Mock Service
6183

@@ -75,17 +97,27 @@ SAM CLI, >= version 0.50.0
7597
AWS CLI
7698
yarn
7799

78-
### Deploy the Backend
100+
### Setup steps
101+
102+
Fork the github repo, then clone your fork locally:
103+
`git clone https://github.com/<your-github-username>/aws-serverless-shopping-cart && cd aws-serverless-shopping-cart`
79104

80-
Clone the project: `git clone <repo-url> && cd <repo-dir>`
105+
If you wish to use a named profile for your AWS credentials, you can set the environment variable `AWS_PROFILE` before
106+
running the below commands. For a profile named "development": `export AWS_PROFILE=development`.
81107

82-
If you wish to use a named profile for your AWS credentials, you can set the environment variable `AWS_PROFILE` before running the below commands. For a profile named "development": `export AWS_PROFILE=development`.
108+
You now have 2 options - you can deploy the backend and run the frontend locally, or you can deploy the whole project
109+
using the AWS Amplify console.
110+
111+
## Option 1 - Deploy backend and run frontend locally
112+
### Deploy the Backend
83113

84-
An S3 bucket will be created for you which will be used for deploying source code to AWS. If you wish to use an existing bucket instead, you can manually set the `S3_BUCKET` environment variable to the name of your bucket.
114+
An S3 bucket will be automatically created for you which will be used for deploying source code to AWS. If you wish to
115+
use an existing bucket instead, you can manually set the `S3_BUCKET` environment variable to the name of your bucket.
85116

86117
Build and deploy the resources:
87118
``` bash
88-
make backend # Creates S3 bucket if not existing already, then deploys CloudFormation stacks for authentication, a product mock service and the shopping cart service.
119+
make backend # Creates S3 bucket if not existing already, then deploys CloudFormation stacks for authentication, a
120+
product mock service and the shopping cart service.
89121
```
90122

91123
### Run the Frontend Locally
@@ -95,16 +127,46 @@ Start the frontend locally:
95127
make frontend-serve # Retrieves backend config from ssm parameter store to a .env file, then starts service.
96128
```
97129

98-
Once the service is running, you can access the frontend on http://localhost:8080/ and start adding items to your cart. You can create an account by clicking on "Sign In" then "Create Account". Be sure to use a valid email address as you'll need to retrieve the verification code.
130+
Once the service is running, you can access the frontend on http://localhost:8080/ and start adding items to your cart.
131+
You can create an account by clicking on "Sign In" then "Create Account". Be sure to use a valid email address as
132+
you'll need to retrieve the verification code.
99133

100-
**Note:** CORS headers on the backend service default to allowing http://localhost:8080/. You will see CORS errors if you access the frontend using the ip (http://127.0.0.1:8080/), or using a port other than 8080.
134+
**Note:** CORS headers on the backend service default to allowing http://localhost:8080/. You will see CORS errors if
135+
you access the frontend using the ip (http://127.0.0.1:8080/), or using a port other than 8080.
101136

102-
## Clean Up
137+
### Clean Up
103138
Delete the CloudFormation stacks created by this project:
104139
``` bash
105140
make backend-delete
106141
```
107142

143+
## Option 2 - Automatically deploy backend and frontend using Amplify Console
144+
145+
146+
[Create a new personal access token](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line)
147+
on GitHub.
148+
Amplify will need this to access your repository. The token will need the “repo” OAuth scope.
149+
150+
Set environment variables:
151+
```bash
152+
export GITHUB_REPO=https://github.com/<your-github-username>/aws-serverless-shopping-cart
153+
export GITHUB_BRANCH=master # Or whichever branch you wish to track
154+
export GITHUB_OAUTH_TOKEN=<github personal access token>
155+
```
156+
157+
Create the Amplify console application, which will provide basic continuous deployment for your Github repository:
158+
``` bash
159+
make amplify-deploy # Creates amplify console application
160+
```
161+
162+
Go to the [AWS Amplify console](https://console.aws.amazon.com/amplify/home), then click on "CartApp" and "run build".
163+
This will deploy both the frontend and backend:
164+
![Amplify Console](./images/AmplifyConsoleScreen.png)
165+
166+
### Clean Up
167+
Delete the CloudFormation stacks created by this project. One is named "CartApp", and then there are 3 with names
168+
starting with "aws-serverless-shopping-cart-".
169+
108170
## License
109171

110172
This library is licensed under the MIT-0 License. See the [LICENSE](LICENSE) file.

amplify-ci/amplify-template.yaml

+2-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Parameters:
1212

1313
OauthToken:
1414
Type: String
15-
Description: GitHub Repository URL
15+
Description: GitHub Personal Access Token
1616
NoEcho: true
1717

1818
SrcS3Bucket:
@@ -44,6 +44,7 @@ Resources:
4444
- "s3:GetObject"
4545
- "s3:CreateMultipartUpload"
4646
- "s3:ListBucket"
47+
- "s3:CreateBucket"
4748
Resource:
4849
- !Sub "arn:aws:s3:::${SrcS3Bucket}"
4950
- !Sub "arn:aws:s3:::${SrcS3Bucket}/*"
@@ -138,8 +139,6 @@ Resources:
138139
Value: nikolaik/python-nodejs:python3.8-nodejs12
139140
- Name: S3_BUCKET
140141
Value: !Ref SrcS3Bucket
141-
- Name: STACKNAME
142-
Value: "aws-serverless-shopping-cart-amplify"
143142
Tags:
144143
- Key: Name
145144
Value: ShoppingCart

amplify.yml

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ backend:
66
phases:
77
preBuild:
88
commands:
9+
- curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
10+
- unzip awscliv2.zip
11+
- ./aws/install
912
- pip3 install --upgrade aws-sam-cli
1013
build:
1114
commands:

images/AmplifyConsoleScreen.png

68 KB
Loading
File renamed without changes.

0 commit comments

Comments
 (0)