Understanding the Add to Cart Functionality in Node.js

Muhammad RanjuMuhammad Ranju
4 min read

Table of contents

Learn how to build add-to-cart functionality in Node.js using MongoDB, Express, and Mongoose for e-commerce applications.

In e-commerce platforms, the ability to add items to a shopping cart is fundamental. This functionality allows users to select products and keep track of them until they proceed to checkout. In this article, we will delve into a Node.js controller that handles adding items to a cart. The controller is part of an Express application and utilizes MongoDB for data storage.

Key Components

  1. Imports and Models
const mongoose = require("mongoose");
const Cart = require("../../../../models/Cart.model/Cart.model");
const Product = require("../../../../models/Products.model/Products.model");
const User = require("../../../../models/User.model/User.model");
const ApiError = require("../../../../utils/ApiError");
const ApiResponse = require("../../../../utils/ApiResponse");
const asyncHandler = require("../../../../utils/asyncHandler");
  • mongoose: A library for MongoDB object modeling.

  • Cart, Product, User: Mongoose models representing collections in the database.

  • ApiError: A custom error handling utility.

  • ApiResponse: A utility to create standardized API responses.

  • asyncHandler: A utility to handle asynchronous functions and errors.

  1. Controller Function Definition

     const createAddTOCartController = asyncHandler(async (req, res) => {
    

    The createAddTOCartController function is defined using asyncHandler to manage asynchronous operations and error handling efficiently.

  2. Extracting Request Data

     const userId = req.user.userId;
     const { productId, quantity = 1 } = req.body;
    

    The function extracts userId, productId, and quantity from the request. If the quantity is not provided, it defaults to 1.

  3. Validating Product ID

     if (!mongoose.Types.ObjectId.isValid(productId)) {
       throw new ApiError(400, "Invalid order id. Please provide a valid order id.");
     }
    

    This validation ensures that the productId is a valid MongoDB ObjectId.

  4. Checking for Missing Fields

     if (!productId) {
       throw new ApiError(400, "Missing required fields: productId and quantity");
     }
    

    An error is thrown if the productId is missing from the request.

  5. Finding Product and User

     const product = await Product.findById(productId);
     const user = await User.findById(userId);
    

    The function queries the database to find the product and user by their respective IDs.

  6. Handling Product Not Found

     if (!product) {
       throw new ApiError(404, "Product not found");
     }
    

    An error is thrown if the product does not exist in the database.

  7. Finding or Creating Cart

     let cart = await Cart.findOne({ userId });
     if (!cart) {
       cart = new Cart({ userId, items: [] });
     }
    

    The function looks for an existing cart for the user. If no cart is found, it creates a new one.

  8. Updating Cart Items

     const existingItem = cart.items.find((item) => item.productId.toString() === productId);
    
     if (existingItem) {
       existingItem.quantity += quantity;
     } else {
       user.carts.push(cart._id);
       await user.save({ validateBeforeSave: false });
    
       cart.items.push({
         productId,
         quantity,
         name: product?.title,
         price: product?.regular_price,
         sku: product?.SKU,
       });
     }
    

    If the item already exists in the cart, its quantity is updated. Otherwise, a new item is added to the cart, and the cart ID is linked to the user's cart array.

  9. Saving the Cart

    await cart.save();
    

    The updated cart is saved to the database.

  10. Creating HATEOAS Links

    const host = req.apiHost;
    const links = [
      {
        rel: "view_cart",
        href: `${host}/carts`,
        method: "GET",
        description: "View Cart",
      },
      {
        rel: "orders",
        href: `${host}/orders`,
        method: "GET",
        description: "Orders",
      },
    ];
    

    HATEOAS (Hypermedia as the Engine of Application State) links provide navigational links to related resources, enhancing API usability.

  11. Returning the Response

    return res.status(201).json(new ApiResponse(201, { cart, links }, "Item added to cart"));
    

    A success response is sent to the client, including the updated cart and HATEOAS links.

  12. Exporting the Controller

    module.exports = createAddTOCartController;
    

    The controller is exported for use in other parts of the application.

Conclusion

This Node.js controller provides a robust and efficient way to manage adding items to a shopping cart. By validating inputs, handling errors gracefully, and maintaining a seamless interaction with the database, the controller ensures a smooth user experience. The inclusion of HATEOAS links further enhances API navigation, making it easier for clients to interact with related resources. This approach not only streamlines the cart management process but also builds a solid foundation for scalable and maintainable e-commerce applications.

This is the actual article repository code link: https://github.com/muhammadranju/e-commerce-api/blob/main/src/api/v1/cart/controller/create.js

This is the main github repository links: https://github.com/muhammadranju/e-commerce-api

1
Subscribe to my newsletter

Read articles from Muhammad Ranju directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Muhammad Ranju
Muhammad Ranju

A JavaScript Backend Developer at Node.js Framework and Database: MongoDB, React.js, Express.js & Node.js MREN Stack Developer