How to Effectively Handle Cart and Cart Items in an E-Commerce Platform
Creating a seamless and efficient shopping cart experience is crucial for any e-commerce platform. Recently, I had the opportunity to build a sophisticated e-commerce solution for a client. I used a modern tech stack comprising-
Nextjs (for frontend)
Strapi - Headless CMS (for backend)
GraphQL (to execute queries and mutations) Learn more about it from here.
I'll dive into the challenges I faced while handling cart creation on the backend, managing CRUD operations on these carts, and the innovative solutions I implemented to overcome these hurdles. Whether you're an experienced developer or just starting, I hope this post provides valuable insights into the intricacies of e-commerce cart management.
Disclaimer: This isn't the only way to handle carts in an e-commerce platform. The approach I used worked well for me in this particular project, and there are multiple ways to achieve similar results.
Problem Statement
The client had a very specific requirement for their E-commerce platform. Apart from offering a wide array of products across multiple categories, they introduced two distinct types of products:
Products (Parent/Primary): These are the main items available for purchase.
Add Ons (Child Products): These supplementary items are designed to enhance or customize the primary products.
A key challenge was that add-on products couldn't exist as standalone items. They are intrinsically linked to a primary product and serve to elevate the value and functionality of the primary product. For example, consider visiting an electronics store to purchase a laptop. If you want to upgrade the RAM of the laptop, you would need to pay an additional amount. The RAM upgrade is an add-on product that cannot be bought separately but is available as an enhancement to the primary laptop product. (well it can be bought separately but you get my point, right? 🤔)
Handling this relationship between primary products and their add-ons, particularly in terms of cart creation and management, was a complex task that required careful consideration and innovative solutions.
Initial Approach: A Total Bust
I won't delve into the exact coding details since this blog focuses on the architecture aspect of it (Maybe in the future we may explore the coding aspect of it). Here's a summary of the initial approach I took, which turned out to be a total bust:
Cart Creation: Every time a user adds a new product to the cart, a new cart is created if one doesn't already exist.
Cart Items: Each product added to the cart results in a new cart item being created. Cart items and products have a 1-to-1 relationship: one product can belong to one cart item, and one cart item can have only one product. The relationship between the cart and cart items is 1-to-many, meaning one cart can have many cart items, but one cart item can't be associated with multiple carts.
Mistake: I made a grave mistake from the get-go. Keep in mind this is my first gig, and everyone makes mistakes. So, please don't judge me too harshly—I promise, I usually know what I'm doing (most of the time). I created different content types for products and add-ons. This resulted in separate entities with very similar properties, which violates database normalization rules and is generally considered a poor design.
Bad Relationship: To add to the damage, I created a one-to-many relationship between products and add-ons.
Initial Happiness: Everything was working buttery smooth and bug-free. I was able to perform CRUD operations on my cart and cart items hassle-free. For example- When I wanted to delete a product from the cart, I would simply call the delete API with the ID of the cart item containing the product ID I wanted to delete. This would also delete the associated add-ons.
Initially, everything seemed fine. I didn't face many difficulties building the frontend and handling all the CRUD operations for the cart and cart items.
When showcasing the progress to my manager, I confidently explained my logic. He immediately called me out, highlighting all the cons of my approach. He pointed out that my design was flawed due to redundant data structures and poor relational design.
I was in denial initially. My manager suggested I come up with a new approach before offering his own. He explicitly stated to consider this as a mini-interview. At that moment, I was still reeling from the realization of my mistake and wasn't ready to accept that I had made a blunder. So I couldn't come up with a new approach on the spot 😔.
This experience was a learning curve, highlighting the importance of proper database design and relational integrity. In the next section, I'll discuss the revised approach I took and how it resolved these issues.
The Solution That Worked
This is a far more refined and efficient solution-
Unified Content Type: First and foremost, remove the separate Add Ons content type altogether and bundle both products and add-ons into the same entity.
Differentiation with a Type Field: To distinguish between products and add-ons, add a new field called "type" with two enum values:
product
andadd_on
.Connecting Parent and Add-ons: The main challenge was how to connect the parent product with its add-ons now that they were combined into a single entity. The solution involved the following steps:
New Fields in Cart Items: Introduce two new fields in the cart items content type:
isParent
: A boolean field that istrue
if the cart item contains a parent product andfalse
if it contains an add-on.parent_id
: A text field that contains the ID of the parent cart item. This field remains empty for parent products for obvious reasons.
This is a diagram explaining the new approach.
This structure ensures that add-ons and their parent products remain connected, making CRUD operations on the cart items straightforward.
On the frontend, I managed a local state to keep track of all products being added to the cart in this format:
[
{
"product_id": 123,
"add_ons": [4, 5, 6]
}
]
By implementing this solution, I was able to overcome the challenges and create a more robust and efficient cart management system.
And remember, in the world of coding, sometimes you need to break a few eggs (or tables) to make a perfectly normalized omelette. Until next time, happy coding!
Subscribe to my newsletter
Read articles from Sahil Wadhwa directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by