Share
Explore

Node.js Express and MONGOOSE Lab: The Shopping List

This will guide students through setting up a Node.js web server using Express.js, with MongoDB as the backend, to create a simple shopping list application.

Instruction Sheet for Building a Shopping List Application

Overview

In this project, you will learn how to build a basic shopping list application where users can add items with their prices and view the list. We will be using Node.js, Express.js, and MongoDB with Mongoose to handle the database operations.
For simplicity, we will develop and test this application locally.

Prerequisites

Basic understanding of JavaScript and Node.js.
Install Node.js and npm (comes with Node.js) on your computer.
Install MongoDB and make sure it is running on your local machine.

Project Initialization

Create a new directory for your project and open it with Visual Studio Code.
Open the integrated terminal in VS Code (`Ctrl + ``).
Initialize a Node.js project by running npm init -y.
Install the necessary npm packages:
npm install express mongoose body-parser dotenv

Project Structure

Here's a basic structure of your project directory:

shopping-list-app/
│ app.js
│ .env
├── models/
│ └── Item.js
├── routes/
│ └── items.js
├── views/
│ └── index.html
└── package.json
Create these files and directories within your project folder now.

Setting Up Express.js Server

Create app.js:
const express = require('express');
const bodyParser = require('body-parser');
const itemRoutes = require('./routes/items');

const app = express();
const port = process.env.PORT || 3000;

// Middleware to parse request bodies
app.use(bodyParser.urlencoded({ extended: true }));

// Static files directory for HTML, CSS, JS
app.use(express.static('views'));

// Routes
app.use('/items', itemRoutes);

// Start the server
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});

MongoDB and Mongoose Setup

In the .env file:
MONGODB_URI=mongodb://localhost:27017/shoppingList
Create models/Item.js:

const mongoose = require('mongoose');

const itemSchema = new mongoose.Schema({
name: String,
price: Number,
});

module.exports = mongoose.model('Item', itemSchema);
Create the routes/items.js file to handle adding and retrieving items:
const express = require('express');
const mongoose = require('mongoose');
const Item = require('../models/Item');
const router = express.Router();

// Connect to MongoDB
mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true });

router.post('/add', async (req, res) => {
const { name, price } = req.body;
const newItem = new Item({ name, price });
try {
await newItem.save();
res.redirect('/');
} catch (error) {
res.status(500).send(error);
}
});

router.get('/list', async (req, res) => {
try {
const items = await Item.find();
res.json(items);
} catch (error) {
res.status(500).send(error);
}
});

module.exports = router;

Frontend HTML Setup

Create views/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shopping List</title>
</head>
<body>
<h1>Shopping List</h1>
<form action="/items/add" method="post">
<input type="text" name="name" placeholder="Item Name" required>
<input type="number" name="price" placeholder="Price" required>
<button type="submit">Add Item</button>
</form>
<div id="items"></div>

<script>
async function getItems() {
const response = await fetch('/items/list');
const items = await response.json();
const itemsList = document.getElementById('items');
itemsList.innerHTML = items.map(item => `<p>${item.name}: ${item.price}</p>`).join('');
}
getItems();
</script>
</body>
</html>

Best Practices and Final Notes

Always test your endpoints with tools like Postman.
Use async/await for asynchronous code to make it more readable.
Keep sensitive information like database URIs in environment variables.
Regularly commit your code to a version control system like Git.
Congratulations! You have created a simple shopping list application that uses MongoDB to store data and Express.js to serve as the backend. Don't hesitate to explore more features and enhance your application as you learn. Happy coding!

To start the application, you would need to first ensure that MongoDB is running on your local machine, then follow these steps:
Start MongoDB: Make sure your MongoDB server is up and running. If you're using a standard installation, MongoDB might start automatically on system startup. If not, you can start MongoDB with the following command (the exact command might differ based on your operating system):
For Linux and macOS systems, you can generally start MongoDB with the command:
mongod
For Windows systems, MongoDB is usually set up as a service, so as long as the service is running, MongoDB should be accessible.
Navigate to Your Project Directory: Use the command line or terminal to navigate to the directory where your app.js file is located. Use cd command to change directories. For example:
cd path/to/your/shopping-list-app
Load Environmental Variables: If you're using environmental variables from a .env file, make sure to load them before starting the app. A common library for this is dotenv which can be included in your project. Ensure the top of your app.js includes the following:
require('dotenv').config();
Install Dependencies: If you haven't already done so, install all of the necessary node packages (dependencies) your project relies on using the following command:
npm install
Start the Server: Run your application with Node.js using the following command:
node app.js
Alternatively, you can use a process manager like nodemon for development purposes. It watches for changes to your source code and automatically restarts your server, which is pretty handy during development. If you don't have nodemon installed, you can install it globally with:
npm install -g nodemon
And then to run your app with nodemon:
nodemon app.js
Access the Application: Once the server is running, you can access your application through a web browser by going to http://localhost:3000/.
Remember that the port number (3000 in this case) should match the one you have set or defined in your app.js file. If you've set up everything correctly, your browser should now display the index page of your shopping list application and you'll be ready to add and view items on your shopping list.

How to use Postman to test the application. Assume no prior knowledge and be explicit from the beginning in every step, instruction and work flow


Instructions for Testing a Node.js Application with Postman


Introduction to Postman

Postman is a popular API client that allows you to design, build, and test API endpoints. It provides a user-friendly interface to send HTTP requests and view responses without needing to set up a front end. This is especially useful in the early development stages of an application.

Step 1: Download and Install Postman

Go to the .
Click on the download button for your operating system (Windows, macOS, or Linux).
After the download is complete, install Postman by following the instructions specific to your operating system.

Step 2: Launch Postman

Open the Postman application on your computer.
You can choose to sign up for a Postman account or use it without signing in. For testing locally, signing in is not required. Click 'Skip signing in and take me straight to the app' if you do not want to create an account.

Step 3: Create a New Request

Click the "New" button in the upper-left corner of the Postman interface.
In the popup window, select "Request" to create a new request.
Give your request a name, such as "Add Shopping Item," and optionally, you can also create a collection to group your requests. This is useful if you are working with multiple endpoints.
Click "Save to" and select the collection or create a new one if prompted, then hit "Save".

Step 4: Configure the Request to Add an Item

With your new request tab open, you'll see a dropdown menu to select HTTP methods next to the URL field. Click on it and select "POST" because you're going to add new data.
In the URL field, enter http://localhost:3000/items/add, replacing 3000 with whatever port your Node.js server is running on.
Now, navigate to the "Body" tab right below the URL field. Here you'll input the data of the item you want to add.
Select the "x-www-form-urlencoded" option which is commonly used to send HTML form data in key-value pairs.
Enter name and price for the key fields, and then provide the values that correspond to the item name and price you wish to add.

Step 5: Send the Request

Click the blue "Send" button on the right side to send the request to your server.
The response will be displayed at the bottom pane. For a successful POST request, you might see a status like '200 OK' and a message indicating that the item was added. If there's an error, you'll see a different status code and an error message which will help in debugging.

Step 6: Test the GET Request to View Items

Create a new request following the same steps as before but this time name it "Get Shopping List" and select "GET" from the dropdown.
For the URL, enter http://localhost:3000/items/list.
After setting the URL, hit "Send".
If the request is successful, in the response body at the bottom, you should see a JSON array of all the items in the shopping list.

Step 7: Review the Results

After you've sent a request, Postman will display the response in the lower section of the window. You can review the status code, response time, and body to understand what is returned from your Node.js application.
Use this information to ensure that your API is working as expected and to troubleshoot any issues.

Final Tips

Save your requests in collections in Postman so you can easily re-use and manage your tests.
Make use of Postman's environments feature if you need to switch between different sets of data, like production and development.
Explore Postman's vast array of features, such as setting up tests and documentation, for more complex API development and testing.
By following the above steps, you'll be able to use Postman effectively to test your Node.js shopping list application or any other APIs.


To modify the schema to accept a price with decimal places, you should use the Number type in Mongoose, which can hold both integer and decimal values. However, due to how JavaScript handles floating point numbers, it's generally a good practice to store currency values in cents as integers to avoid precision issues. This way, you would store 237 for $2.37.

But since you asked to enter 2.37 directly, here is the schema modification:
const mongoose = require('mongoose');

const itemSchema = new mongoose.Schema({
name: {
type: String,
required: true // Ensures name is provided
},
price: {
type: mongoose.Types.Decimal128,
required: true // Ensures price is provided
}
});

module.exports = mongoose.model('Item', itemSchema);
By using mongoose.Types.Decimal128, you're specifying the price field to use the Decimal128 format of BSON type, which is a decimal floating-point format capable of precisely representing decimal numbers, including currency.
When you retrieve the price from the database, Mongoose will give you a Decimal128 object. To convert it back to a string, you can call item.price.toString().
However, if you simply want the schema to accept floating-point values and you're not concerned with potential floating-point precision issues, you can leave it as Number:
const mongoose = require('mongoose');

const itemSchema = new mongoose.Schema({
name: {
type: String,
required: true // Ensures name is provided
},
price: {
type: Number,
required: true // Ensures price is provided
}
});

module.exports = mongoose.model('Item', itemSchema);
This code indicates the price to use JavaScript's standard Number type, which can store floating point values. However, be aware that floating point arithmetic may lead to precision issues especially when dealing with financial calculations or comparisons.


Exercise B: Display the amount of money $$$pent

To display the total amount of money of the shopping list at the top of the page, and to add CSS for a cheerful floral theme with pink, orange, and chartreuse colors, you will need to modify both the backend (to calculate the total) and the front-end (to include the new selector and CSS).

Let's start by modifying the backend to calculate the total amount. For simplicity of this example, I'm not modifying the schema to store currency in the most optimal way, but I'm modifying the endpoint to calculate and send the total to the front-end.

Backend Changes (Node.js with Express)

Modify your routes/items.js to calculate the total:
// Add this endpoint to get the total
router.get('/total', async (req, res) => {
try {
const items = await Item.find();
const total = items.reduce((acc, item) => acc + item.price, 0); // Calculate the total
res.json({ total: total.toFixed(2) }); // Send back a nicely formatted string
} catch (error) {
res.status(500).send(error);
}
});

Frontend Changes (HTML and CSS)

Modify your views/index.html to include the total and floral theme:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Shopping List</title>
<style>
body {
background: floralwhite;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.shopping-total {
color: chartreuse;
font-size: 1.5em;
font-weight: bold;
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.form-add {
background: pink;
padding: 20px;
border-radius: 8px;
}
button {
background: orange;
border: none;
padding: 10px 20px;
color: white;
border-radius: 5px;
cursor: pointer;
}
.item-list {
margin-top: 20px;
}
.item {
background: lightyellow;
border: 1px solid orange;
margin-bottom: 10px;
padding: 10px;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1>Shopping List</h1>

<!-- Total Amount Display -->
<div id="total" class="shopping-total">Total: $0.00</div>

Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.