In this post, we'll be looking at creating a model of a shopping cart. We will be using OpenJS Architect for the infrastructure as code and deployment framework. We will be deploying to AWS cloud through Begin. No other frameworks will be needed as we'll be developing this app with just HTML forms, GET, and POST requests. The cart will even work with javascript disabled!
Create a new Architect project
We can create a new Architect project from the command line, the only prerequisite is having Node.js installed.
npm init @architect ./shopping
cd shopping
npm i @architect/functions @begin/data
We're adding two dependencies that we will need to make things easier, @architect/functions and @begin/data. These two libraries will make things easier as we work with AWS Lambda functions and DynamoDB.
Modify the app.arc
file
The app.arc
file is our infrastructure as code file. It tells Architect what resources to deploy and gives structure to the underlying source code. Open up the app.arc
file in the root of your project and modify it with the following:
@app
shopping
@http
get /
post /cart
post /cart/delete
@tables
data
scopeID *String
dataID **String
ttl TTL
After you modify the app.arc
file, run arc init
from the command line to scaffold out the functions that we will need.
There are three routes and a declaration of a data table. Each route will have a corresponding Lambda handler that is a discrete function. We'll be using @begin/data as a DynamoDB client to interact with the database.
Modify the get-index
route
The first route we'll look at is the get-index
route, which is called at the apex of the application.
let arc = require('@architect/functions')
let data = require('@begin/data')
async function http (req) {
let result = await data.get({
table: 'shopping-cart'
})
return {
statusCode: 200,
headers: {
'cache-control': 'no-cache, no-store, must-revalidate, max-age=0, s-maxage=0',
'content-type': 'text/html; charset=utf8'
},
body: `
<h1> Praise Cage </h1>
<p> Welcome to the Store </p>
<ul>
<li>Item 1</li>
<form action='cart' method='POST'>
<input type="number" name="quantity"/>
<input type="hidden" name="productId" value='001'>
<button>Add to Cart</button>
</form>
<form action='cart/delete' method='POST'>
<input type="hidden" name="productId" value='001'>
<button>Remove from Cart</button>
</form>
<li>Item 2</li>
<form action='cart' method='POST'>
<input type="number" name="quantity"/>
<input type="hidden" name="productId" value='002'>
<button>Add to Cart</button>
</form>
<form action='cart/delete' method='POST'>
<input type="hidden" name="productId" value='002'>
<button>Remove from Cart</button>
</form>
<li>Item 3</li>
<form action='cart' method='POST'>
<input type="number" name="quantity"/>
<input type="hidden" name="productId" value='003'>
<button>Add to Cart</button>
</form>
<form action='cart/delete' method='POST'>
<input type="hidden" name="productId" value='003'>
<button>Remove from Cart</button>
</form>
</ul>
<p>This is your order</p>
<ul>${result.map(item => `<li>${JSON.stringify(item.cartItem)}</li>`).join('')}</ul>
`
}
}
exports.handler = arc.http.async(http)
In this function, we are returning a string of HTML that will be rendered by the browser. Congratulations, you now have done server-side rendering with a serverless function!
Adding a database layer
You should notice that we are using @begin/data in the get-index
route to grab all the cart data before the page loads and we will render that at the bottom of the page. In a future tutorial, we will look at styling this page, but for now, we will just return JSON of the objects in the database.
Modify the post-cart
route
The post-cart
route is where we will update our cart with the different items that are available.
let arc = require('@architect/functions')
let data = require('@begin/data')
async function http (req) {
await data.set({
table: "shopping-cart",
key: req.body.productId,
cartItem: {
quantity: req.body.quantity,
prodId: req.body.productId
}
})
return {
statusCode: 302,
location: '/'
}
}
exports.handler = arc.http.async(http)
Modify the post-cart-delete
route
The post-cart-delete
handler is responsible for deleting the item from the cart. Again it uses the @begin/data DynamoDB client. For more information about @begin/data, check out the docs.
let arc = require('@architect/functions')
let data = require('@begin/data')
async function http(req) {
await data.destroy({
table: "shopping-cart",
key: req.body.productId
})
return {
statusCode: 302,
location: '/'
}
}
exports.handler = arc.http.async(http)
With this last handler, we can now run npm start
and see the results of our app thus far.
You should be seeing an unstyled page.
Next steps
In a follow-up tutorial, we will take a look at styling the cart so it will look a bit nicer.
Full code repo can be found at https://github.com/pchinjr/shopping-cart
Top comments (0)