Project D
- Released
-
11 November 2021 - Submission
-
Deadline 25 November 2021 @ 5 PM EDT Where Web Submit Name D Files
index.js dao.js script.js - Version
-
1.10 25 November 2021 Fix typo in Product view in index.html. 1.9 17 November 2021 Fix submit command in Section E. 1.8 17 November 2021 Fix UI bug on Firefox in index.html and style.css. 1.7 17 November 2021 Fixed typos, add hints and clarifications in script.js. 1.6 13 November 2021 Fixed typo in script.js, line 102. 1.5 13 November 2021 Minor update to script.js. 1.4 13 November 2021 Fixed UI bug in index.html, style.css and script.js. 1.3 12 November 2021 Added reference implementation: here. 1.2 12 November 2021 Added developer tips: here, here, and here. 1.1 12 November 2021 Updated GET /api/products/:id
error response.1.0 11 November 2021 Initial Release
Table of contents
Executive Summary
In this project we build a complete shopping-cart web application with an SPA frontend and a TCP, Tomcat, and NodeJS backend.
The Environment
For the client-side frontend (i.e. HTML, CSS, and JavaScript), any simple text editor (such as nano or vim) will do, but if you prefer to work in a GUI environment then a few possibilities that come to mind include Atom, Sublime, Eclipse, and VScode.
To serve the frontend from Tomcat, store its files under the WebContent/
directory. For Node, use the middleware app.use(express.static(path.join(__dirname, 'public')));
. If you serve the frontend from one endpoint and invoke services from another, you may need to include the header Access-Control-Allow-Origin: *
in the service’s response to get around the cross-domain scripting policy of the browser.
The Backend
You will be using the services you created in Projects A through C plus the following four (which were discussed in class). It is up to you to implement these four in Java (Tomcat) or in JavaScript (Node and Express). For your database access, it is also up how you implement it in Node. You may use the sqlite3
module directly or use the sequelize
object-relational mapping (ORM) module.
This is a simplify/modified version of the Products and Cart REST APIs. While you may use my provided implementations as references or for inspiration, implement YOUR OWN from scratch.
GET /api/products/category/:id
This service filters the products in the Product table of the Models_R_US.db
database (which resides in ~/4413/pkg/sqlite
) given the category :id
and responses with an array of the Products belonging to that category. The response should be mimetyped as “application/json” and should be an array of JSON objects, each representing a Product, with at least the following properties:
Properties | Type | Description |
---|---|---|
id | string | The unique identifier for each Product. |
catId | number (int) | The category for which the Product belongs. |
name | string | The user-friendly descriptive name of the Product. |
description | string | The long description about the Product. |
cost | number | The listed price of the Product. |
GET /api/products/:id
This service returns a single product in the Product table of the Models_R_US.db
database (which resides in ~/4413/pkg/sqlite
) given the product’s ID. The response should be mimetyped as “application/json” and should be an JSON object representing the Product, with at least the following properties:
Properties | Type | Description |
---|---|---|
id | string | The unique identifier for each Product. |
catid | number (int) | The category for which the Product belongs. |
name | string | The user-friendly descriptive name of the Product. |
description | string | The long description about the Product. |
cost | number | The listed price of the Product. |
If there is no Product with the given :id
, send the HTTP status code 404 Not Found
.
GET /api/cart
This service returns all of the items in the cart. It responses with the cart as an array of JSON objects. Each JSON object has two fields:
Properties | Type | Description |
---|---|---|
id | string | The unique identifier for each Product. |
qty | int | The number of items for that Product. |
No two entries in the cart array should have the same Product ID. When there are no items in the cart, it returns an empty array.
POST /api/cart/update
This service takes a JSON object in the body of a POST request and responses with the updated cart as an array of JSON objects, just like GET /api/cart
. In the POST request, the JSON object should have the following fields:
Properties | Type | Description |
---|---|---|
id | string | The unique identifier for a particular Product. |
qty | int | The number of items for that Product the cart should be updated to. |
- If the qty is 0 or negative, the item is deleted from the cart.
- If the item was not in the cart to begin with and the qty is non-positive, nothing changes.
- If the item was not in the cart and the qty is positive, it is added to the cart with that value.
- Lastly, if the item was previously in the cart and the qty is positive, the new qty replaces the old qty.
Handling the Request Body
To automatically process the POST request body as JSON, add this middleware to your
index.js
. (Near the top where the session is setup).// Use middleware to parse request body as JSON. // bodyParser is deprecated and now merged into express itself. app.use(express.json());
The Frontend
Now, you are going to develop a webapp using the above API services and the services from your previous labs (namely Catalog
from Project C). Provided are the index.html, style.css, and a template for your script.js. Your project should be structured as follows:
.
├── public
│ ├── css
│ │ └── style.css
│ ├── js
│ │ └── script.js
│ └── index.html
├── node_modules
├── dao.js
├── index.js
└── package.json
Serve Static Files
To serve static files such as images, CSS files, and JavaScript files, use the
express.static
built-in middleware function in ExpressJS and add it to yourindex.js
.// Use middleware to serve static files from the public directory. app.use(express.static(path.join(__dirname, 'public')));
Cross-Origin Resource Sharing (CORS)
Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources. CORS also relies on a mechanism by which browsers make a “preflight” request to the server hosting the cross-origin resource, in order to check that the server will permit the actual request. In that preflight, the browser sends headers that indicate the HTTP method and headers that will be used in the actual request. To enable CORS, add this middleware function to your
index.js
:// Enable CORS app.use((req, res, next) => { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "*"); next(); });
Learn more: here.
For a reference implementation, see: here.
For detailed instructions on what you need to do, see the comments included within the script.js
and index.html
. Look for the TODO
s. Here is a brief summary of each view:
Catalog View
Upon visiting the single-page application (SPA) frontend, the user should be presented with all the product categories. Only the name of each category should be visible; the id should not. The user can click on a category to select it.
Category View
All products belonging to the selected category are displayed. Only the name of each product should be visible; the id should not. The display is divided into three columns. On the left is an image that doubles as the Title and category identifier as well as the back button to return to the Catalog View. In the center is a list of items that belong to that category. The user can click on a product to select it. The right is left blank for Product details in the Product view.
Product View
The Product view fills in the right panel in the Category view. All details of the selected product are displayed. The user can click a ‘Add to Cart’ button to add the product to the cart. This view includes the id, name, description and cost of the Product.
Cart View
Once an item is added to the cart, this view is displays the items added in a table. The table has five columns: ID, Name, Cost, Quantity and Update. The first three columns simply show the ID, name and cost for each Product in each row. The quantity column contains input field populated with the current number of items in the cart for that Product. The user can change the quantity of any products and click the Update button residing in the Update column to modify item.
Additionally, at the top of the page is a navigation bar with a title and a cart button. This persists on the page regardless of the view. The user click on the title to go to the Catalog view or the cart button to go to the Cart view at time. With each view change, the URL of the page is dynamically updated without refreshing the page. The URLs are bookmarkable and linkable, i.e.: entering the URL in the web browser’s address bar should take the user directly to the view associated with that URL as if it were a static file.
Submitting Your Work
Simply upload your index.js
, dao.js
and script.js
to the course cloud so you can use it during tests. (You can also upload it to your Github, Google Drive, DropBox, S3, or some other cloud service).
$ submit 4413 D index.js dao.js public/js/script.js