This is an eCommerce store web-application, with the frontend built in Javascript and React, and the backend built with NodeJS hosted using AWS.
This app includes the features of a webshop but also includes user authentication, email confirmation, and payments
Use this card for payments
Card# | Expiry Date | CVC |
---|---|---|
4242 4242 4242 4242 |
04/24 |
242 |
Sample User
password | |
---|---|
[email protected] |
test123! |
As a shopper, I would like to:
- view items for sale.
- add an item to my shopping bag.
- view my shopping bag.
- update the quantity of an item in my shopping bag.
- remove an item from my shopping bag.
- clear all items from my shopping bag.
- have the items in my bag saved for next time.
- place an order.
- receive an email confirmation of my order placement.
- view my previous purchases.
The backend of the application is where the business logic is implemented. The code is hosted on AWS Lambda functions, and each function is fronted by an API Gateway rest API. Each Lambda function handles requests for one endpoint.
The application saves all items in two DynamoDB tables. The user-table is exclusively for user authentication and the e-Commerce table stores all other items, such as orders, products and cart items.
The API for the this application is as follows:
POST /users
POST /login
GET /products
GET /cartItems
DELETE /cartItems
PUT /cartItems/{productId}
DELETE /cartItems/{productId}
POST /orders
GET /orders
GET /orders/{orderId}
POST /orders/{orderId}
Status Code | Description |
---|---|
200 | OK |
401 | Unauthorized |
500 | INTERNAL SERVER ERROR |
Below are sample requests and responsesss for each endpoint, ($ specifies an optional parameter)
Request
''
Response
[
{
"image": "{imageURL}",
"SK": "product#123",
"PK": "product",
"description": "Tasty berries!",
"inStock": 50,
"price": 2,
"name": "Saskatoon Berries",
"productId": "123"
}
]
Request
Authorization: "Bearer {accessToken}"
Response
[
{
"image": "{imageURL}",
"SK": "cart#100",
"PK": "[email protected]",
"price": 2,
"name": "Saskatoon Berries",
"productId": "100"
}
]
Request
Authorization: "Bearer {accessToken}"
Response
''
Request
Authorization: "Bearer {accessToken}"
{
"price": 10,
"name": "apple pie",
"productId": "130",
"quantity": 1,
"image": "{imageURL}"
}
Response
''
Request
Authorization: "Bearer {accessToken}"
Response
''
Request
$Authorization: "Bearer {accessToken}" (optional)
{
"paymentMethodId": "{payment_method_id}",
"cartItems": [
{
"price": 2,
"name": "Saskatoon Berries",
"productId": "100",
"quantity": 4
}
],
"shippingData": {
"firstName": "John",
"lastName": "Doe",
"email": "[email protected]",
"address1": "123 Main St",
"city": "Winnipeg",
"zip": "1B1 2A2",
"province": "Manitoba",
"country": "Canada"
},
"amount": 400
}
Response
------ if success -------
''
--------- else ----------
{
error: "{errorMessage}
}
Request
Authorization: "Bearer {accessToken}"
Response
[
{
"orderId": "111",
"status": "paid",
"createdAt": 1635737407,
"amount": 1500
}
]
Request
Authorization: "Bearer {accessToken}"
Response
[
{
"quantity": 1,
"orderId": "111",
"name": "Honey Dill Sauce",
"productId": "123"
},
{
"quantity": 1,
"orderId": 111,
"name": "Apples",
"productId": "321"
}
]
Request
{
"email": "[email protected]",
"password": "password1!"
}
Response
------ if success -------
{
accessToken: "{accessToken}"
}
--------- else ----------
{
"emailExists": true
}
Request
{
"email": "[email protected]",
"password": "password1!"
}
Response
------ if success -------
{
accessToken: "{accessToken}"
}
--------- else ----------
{
"loginFailed": "{message}"
}
eCommerceTable
Entity | PK | SK |
---|---|---|
Product | product |
product# productId |
CartItem | cart# productId |
|
Order | order# productId |
|
OrderItem | orderItem# orderId |
orderItem# productId |
BlackListedEmail |
userTable
Entity | PK | SK |
---|---|---|
user | hashedPassword |
Access patterns | Query Condition |
---|---|
Get all products for sale. | PK = product , SK begins_with( product ) |
Get/remove all the items in a customer's cart. | PK = email, SK begins_with( cart ) |
Get the past orders of a customer. | order# productId |
Get all the items for a given order. | PK = orderItem# orderID, SK begins_with( orderItem ) |
Create a file named config.yml with the following variables
ACCESS_TOKEN_SECRET: 'x'
STRIPE_SECRET_KEY: 'y'
To get a stripe secret key you will need to create an account.
From the backend folder:
npm install
sls deploy
Creating a SES resources for sending emails through CloudFormation is not supported in Canada, so some manual configuration using the aws-cli and the console must be done.
-
Create a configuration set in the Amazon SES console with the same name as the 'CONFIGURATION_SET_NAME' variable defined in the serverless.yaml file
-
Attach the SNS topic created during deployment to the configuration set
- Select
bounce
andcomplaint
as the event types
- Select
-
To create the email template:
aws ses update-template --cli-input-json file://sendEmailConfirmation/emailTemplate/emailTemplate.json
The products, cart and checkout pages were inspired by this tutorial video https://www.youtube.com/watch?v=377AQ0y6LPA&ab_channel=JavaScriptMastery
To run the application locally, from the frontend-react folder:
npm install
npm start