Data from session is not added but it is recreated while testing with client side

Viewed 194

This thing works on server side fine for me, session successfully adds data in a cart as it should. But on client side (I'm using axios) the session is constantly being recreated. By recreating the data I mean for example when I try to add more items in cart, whole the time quantity is still 1 and it is being recreated constantly with last item.

This is file where I use session:

app.use(session({
    secret: "hideSession",
    resave: true,
    saveUninitialized: true,
    cookie: {
        sameSite: true,
        httpOnly: false,
    }
  }));

Whole add_to_cart route request:

app.post("/add_to_cart/:name", async (req, res) => {

    let db = await connect();
    let cursor = await db.collection("products").find({})
    let finalData = await cursor.toArray();
    const name= req.params.name;

    const singleDrink = await finalData.find((product) => product.name === name);
    let cart;
    if (!req.session.cart) req.session.cart = cart = new Cart({});

    else cart = new Cart(req.session.cart);

    req.session.cart = cart;
    cart.addDrink(singleDrink);
    console.log(req.session.cart,req.session.cookie)
    res.send(cart);
});  

client side using axios:

let Cart = {
    addToCart(name){
            return Service.post(`/add_to_cart/${name}`)
        }
    }

client side passing function from axios:

async sendCartData(name){
                Cart.addToCart(name);
            }

And button:

<p @click="sendCartData(item.name)" class="btn btn-default add-to-cart"><i class="fa fa-shopping-cart"></i>Add to cart</p>

This is Cart file:

module.exports = function Cart(oldCart) {
    this.products = oldCart.products || {};
    this.totalQty = oldCart.totalQty || 0;
    this.totalPrice = oldCart.totalPrice || 0.00;
  
    this.addDrink = function(item) {
      let storeItem = this.products;
      if (!storeItem.hasOwnProperty("item")) {
        
        storeItem = this.products = {item: item};
        this.totalQty = 1;
        this.totalPrice = parseFloat(item.price);
  
      } else {
  
        storeItem = {item: item};
        this.products = storeItem;
        Object.defineProperties(storeItem, {
            currentQty: {
                enumerable: false,
                writable: true
            },
            price: {
                enumerable: false,
                writable: true
            }
        },
        
        );
        storeItem.currentQty++;
        storeItem.price = parseFloat(storeItem.item.price * storeItem.currentQty);
        this.totalQty++;
        this.totalPrice += parseFloat(storeItem.item.price);
      }
    }
  }
2 Answers

I have a theory, so not sure that it is the problem you have.

You seem to use the default session storage which is MemoryStore. With this storage, if application restart due for example to an exception, session in memory are lost.

In this case, your test if (!req.session.cart) is true and then session is recreated.

To verify this check the error log.

and also change the session storage for a disk persist storage. You'll find a list here: https://www.npmjs.com/package/express-session#compatible-session-stores

If you want to have performance of an in memory storage AND security of a disk persist storage, take a look at loki.js which is in this list :https://www.npmjs.com/package/connect-loki

Seems to work

I copied the code you've shared and ran it locally and it does appear to work. I tested by entering the path /add_to_cart/:name directly in the browser address bar. I was able to confirm that the cart numbers are incremented.

I was able to confirm also that Session ID is consistent across requests. If this is NOT the case with the rest of your code, then something is deleting your session and you'll need to troubleshoot that (respond in comments if so).

enter image description here

enter image description here

Cart needs improvement

That being said, your cart logic seems extremely overcomplicated (making properties non-enumerable, reassigning variables to themselves) and somewhat broken. It is only able to track a single item, and storeItem.currentQty and storeItem.price are always NaN. Your cart should keep an array of the added item IDs and the quantities of each. Here is an example implementation of a cart:

  items;
  constructor(oldCart) {
    this.items = oldCart?.items ?? [];
  }

  addDrink(item) {
    let cartItem = this.items.find(i => i._id == item._id);
    if (cartItem == null) {
      cartItem = {
        _id: item._id,
        qty: 0,
        unitPrice: parseFloat(item.price),
      };
      this.items.push(cartItem);
    }
    cartItem.qty++;
  }
  get totalQty() {
    return this.items.reduce( (totalQty, item) => totalQty += item.qty, 0);
  }
  get totalPrice() {
    return this.items.reduce( (totalPrice, item) => totalPrice += item.qty * item.unitPrice, 0.00);
  }
}

Note that in this implementation, the item descriptions are not cached and would have to be retrieved from the database if they are to be displayed - you may want to add a description in as needed.

Related