Build a Node.js Interactive Web-Based Expense Tracker

Written by

in

Managing finances can feel like navigating a maze, but it doesn’t have to be daunting. Whether you’re a student, a freelancer, or simply someone looking to get a better handle on your spending, tracking your expenses is a crucial first step. In this tutorial, we’ll build a simple yet functional web-based expense tracker using Node.js. This project is perfect for beginners and intermediate developers who want to deepen their understanding of Node.js, Express.js, and basic front-end concepts. We’ll create a user-friendly interface where users can add, view, and categorize their expenses. By the end of this guide, you’ll not only have a practical application but also a solid foundation for building more complex web applications.

Why Build an Expense Tracker?

Expense tracking offers several benefits:

  • Improved Financial Awareness: Knowing where your money goes is the first step towards better financial decisions.
  • Budgeting Made Easier: Track spending against your budget to identify areas where you can save.
  • Goal Setting: Monitor progress towards financial goals, such as saving for a down payment or paying off debt.
  • Financial Control: Take control of your finances and make informed choices.

Building this expense tracker will allow you to:

  • Learn the fundamentals of Node.js and Express.js.
  • Understand how to handle HTTP requests (GET, POST, etc.).
  • Work with basic HTML, CSS, and JavaScript for the front-end.
  • Practice using a database (we’ll use a simple in-memory database for this tutorial).
  • Gain experience in building a full-stack web application.

Prerequisites

Before we begin, make sure you have the following installed on your system:

  • Node.js and npm (Node Package Manager): You can download these from the official Node.js website: https://nodejs.org/.
  • A text editor or IDE: VS Code, Sublime Text, or Atom are excellent choices.
  • Basic understanding of HTML, CSS, and JavaScript: While we’ll keep the front-end simple, some familiarity is helpful.

Project Setup

Let’s get started by setting up our project directory and installing the necessary dependencies.

  1. Create a Project Directory: Open your terminal or command prompt and create a new directory for your project:
    mkdir expense-tracker
    cd expense-tracker
  2. Initialize npm: Initialize a new Node.js project using npm. This will create a package.json file, which will manage our project’s dependencies:
    npm init -y
  3. Install Dependencies: We’ll need Express.js for our web server and a templating engine (we’ll use EJS, Embedded JavaScript) to render dynamic HTML. Install these dependencies:
    npm install express ejs

Setting Up the Server (index.js)

Create a file named index.js in your project directory. This file will contain the code for our server. Let’s start by importing the necessary modules and setting up a basic Express app:

// index.js
const express = require('express');
const app = express();
const port = 3000;

// Middleware to parse JSON and URL-encoded data
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Set the view engine to EJS
app.set('view engine', 'ejs');

// Sample expenses data (in-memory database)
let expenses = [
    { id: 1, description: 'Groceries', amount: 50, category: 'Food' },
    { id: 2, description: 'Movie Ticket', amount: 15, category: 'Entertainment' }
];

// Routes (we'll add these later)

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

Let’s break down this code:

  • Importing Modules: We import the express module to create our server and assign it to the app variable.
  • Setting the Port: We define the port number (3000).
  • Middleware: express.json() and express.urlencoded({ extended: true }) are middleware functions that parse incoming requests with JSON payloads and URL-encoded payloads, respectively. This allows us to easily access data sent from forms.
  • Setting the View Engine: We tell Express to use EJS as our templating engine. EJS will allow us to dynamically generate HTML.
  • Sample Data: We create a sample expenses array. In a real-world application, this data would be stored in a database.
  • Starting the Server: We use app.listen() to start the server and listen for incoming requests on the specified port. We also log a message to the console to confirm that the server is running.

Creating the Routes

Now, let’s define the routes for our expense tracker. We’ll need routes to:

  • GET /: Display the expense tracker page (showing the list of expenses).
  • POST /expenses: Add a new expense.

Add the following code inside the index.js file, before the app.listen() call:

// GET / - Display the expense tracker
app.get('/', (req, res) => {
    res.render('index', { expenses: expenses }); // Render the 'index.ejs' view and pass the expenses data
});

// POST /expenses - Add a new expense
app.post('/expenses', (req, res) => {
    const newExpense = {
        id: expenses.length + 1,
        description: req.body.description,
        amount: parseFloat(req.body.amount), // Convert amount to a number
        category: req.body.category
    };
    expenses.push(newExpense);
    res.redirect('/'); // Redirect back to the home page
});

Let’s explain these routes:

  • GET /:
    • When a user visits the root path (/), this route is triggered.
    • res.render('index', { expenses: expenses }) renders the index.ejs view, passing the expenses data to it.
  • POST /expenses:
    • This route handles the submission of the expense form.
    • req.body contains the data submitted from the form (description, amount, and category).
    • We create a newExpense object with the form data, generate a unique ID, and add it to the expenses array.
    • res.redirect('/') redirects the user back to the home page (/) after adding the expense, so the updated list of expenses is displayed.

Creating the Views (index.ejs)

Now, let’s create the index.ejs file, which will contain the HTML for our expense tracker. Create a new directory named views in your project directory. Inside the views directory, create a file named index.ejs. Add the following code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Expense Tracker</title>
    <style>
        body {
            font-family: sans-serif;
            margin: 20px;
        }
        h2 {
            margin-bottom: 10px;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 20px;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }
        th {
            background-color: #f2f2f2;
        }
        form {
            margin-bottom: 20px;
        }
        label {
            display: block;
            margin-bottom: 5px;
        }
        input[type="text"], input[type="number"], select {
            width: 100%;
            padding: 8px;
            margin-bottom: 10px;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box;
        }
        button {
            background-color: #4CAF50;
            color: white;
            padding: 10px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <h2>Expense Tracker</h2>

    <form action="/expenses" method="POST">
        <label for="description">Description:</label>
        <input type="text" id="description" name="description" required>

        <label for="amount">Amount:</label>
        <input type="number" id="amount" name="amount" step="0.01" required>

        <label for="category">Category:</label>
        <select id="category" name="category" required>
            <option value="Food">Food</option>
            <option value="Entertainment">Entertainment</option>
            <option value="Housing">Housing</option>
            <option value="Transportation">Transportation</option>
            <option value="Other">Other</option>
        </select>

        <button type="submit">Add Expense</button>
    </form>

    <table>
        <tr>
            <th>Description</th>
            <th>Amount</th>
            <th>Category</th>
        </tr>
        <% expenses.forEach(expense => { %>
            <tr>
                <td><%= expense.description %></td>
                <td><%= expense.amount %></td>
                <td><%= expense.category %></td>
            </tr>
        <% }); %>
    </table>
</body>
</html>

Let’s break down this HTML:

  • Basic HTML Structure: We start with the standard HTML structure, including the <head> and <body> sections.
  • CSS Styling: We’ve included basic CSS styling within the <style> tags to make the expense tracker visually appealing. This includes styles for the body, headings, tables, forms, and buttons.
  • Expense Form: The <form> section contains the form for adding new expenses. It includes input fields for description, amount, and category, as well as a submit button. The action="/expenses" attribute specifies that the form data will be sent to the /expenses route, and the method="POST" attribute specifies that the form data will be sent using the POST method.
  • Expense Table: The <table> section displays the list of expenses.
  • EJS Templating: We use EJS syntax (<% ... %> and <%= ... %>) to dynamically generate the table rows. The <% expenses.forEach(expense => { %> loop iterates through the expenses array (passed from the server), and for each expense, it creates a table row (<tr>) with the expense’s description, amount, and category. <%= expense.description %>, <%= expense.amount %>, and <%= expense.category %> output the values of the expense properties.

Running the Application

Now that we’ve set up the server, the routes, and the view, let’s run our expense tracker. Open your terminal or command prompt, navigate to your project directory (expense-tracker), and run the following command:

node index.js

This will start the server, and you should see the message “Server is running on http://localhost:3000” in your terminal. Open your web browser and go to http://localhost:3000. You should see the expense tracker interface. You can now add new expenses using the form, and they will be displayed in the table.

Common Mistakes and Troubleshooting

Here are some common mistakes and how to fix them:

  • Incorrect Dependencies: Double-check that you have installed all the necessary dependencies (express and ejs) using npm install.
  • Typographical Errors: Carefully review your code for any typos, especially in the route definitions, variable names, and file paths.
  • Incorrect File Paths: Ensure that the file paths in your code (e.g., the path to index.ejs) are correct.
  • Server Not Running: If you’re not seeing anything in your browser, make sure the server is running in your terminal. If the server is not running, try running the command node index.js again.
  • Form Not Submitting: Make sure the action attribute in your form is correct (e.g., action="/expenses") and that the form method is set to POST. Also, verify that the name attributes of your input fields match the names you are using in your server-side code.
  • Amount Not Being Parsed Correctly: The amount may not be correctly parsed from the form data. Ensure you are using parseFloat(req.body.amount) to convert the amount to a number.

Enhancements and Future Improvements

This is a basic expense tracker, and there are many ways to enhance it:

  • Database Integration: Instead of using an in-memory database, connect to a real database (e.g., MongoDB, PostgreSQL, or MySQL) to store and retrieve expense data. This will allow you to persist the data even after the server restarts.
  • User Authentication: Implement user authentication so that only authorized users can access their expense data.
  • Data Validation: Add data validation to the form to ensure that the user enters valid data (e.g., the amount is a positive number).
  • More Detailed Reporting: Add features such as the ability to generate reports and charts to visualize expenses.
  • Categories: Allow users to create and manage custom expense categories.
  • Date Selection: Add a date picker to allow users to specify the date of the expense.
  • Edit and Delete Functionality: Allow users to edit and delete existing expenses.
  • Styling: Improve the user interface with more advanced CSS and potentially a CSS framework like Bootstrap or Tailwind CSS.

Key Takeaways

In this tutorial, we’ve built a simple web-based expense tracker using Node.js and Express.js. We’ve covered the basics of setting up a Node.js project, creating routes, rendering views with EJS, and handling form submissions. You’ve also learned how to use middleware to parse incoming data. This project provides a solid foundation for building more complex web applications with Node.js.

FAQ

  1. How do I deploy this application?

    You can deploy this application to a cloud platform like Heroku, AWS, or Google Cloud. You’ll need to set up a deployment environment and configure the platform to run your Node.js application.

  2. Can I use a different templating engine?

    Yes, you can. Popular alternatives to EJS include Pug (formerly Jade) and Handlebars. You’ll need to install the appropriate package and modify your code to use the syntax of the chosen templating engine.

  3. How can I add more features?

    Start by identifying the features you want to add (e.g., user authentication, database integration). Then, modify your code to implement those features. This might involve creating new routes, updating your view templates, and interacting with a database.

  4. What is middleware?

    Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. They can perform tasks such as parsing request bodies, handling authentication, or logging requests.

Building this expense tracker, even in its basic form, provides a practical introduction to full-stack web development. The ability to create, manage, and display data through a web interface is a fundamental skill. As you continue to learn and experiment with Node.js, Express.js, and other technologies, you’ll be able to build increasingly sophisticated and useful applications. The journey of learning to code is a continuous process of building, experimenting, and refining; embrace the challenges, and celebrate the small victories along the way. Your growing skills will unlock new possibilities, empowering you to create and innovate with technology.