How to handle objects of a certain class in express sessions?

Viewed 169

I am new to nodejs/express and currently trying to figure out how to store objects of a certain class in session storage (which I understand is basically a serialized version of the req.session object).

My (shortened example is this):

//cart.js
const CartItem = require('./cartItem');

class Cart {

    _items = [];

    constructor() {
        // ...
    }

    // ...

    addItem(item) {
        // ...
    }
}

module.exports = Cart;
//routes.js    
router.get('/create', function (req, res, next) {
    req.session.cart = new Cart();
    req.session.cart.addItem(new CartItem('Red Sox', 15, Math.round(Math.random() * 5)));

    console.log(req.session);

    res.render('cart/create.twig', {
        cart: req.session.cart
    });
});

router.get('/overview', function (req, res, next) {
    console.log(req.session);

    res.render('cart/overview.twig', {
        cart: req.session.cart
    });
});

The problem I am facing is that during the first action (router.get('/create') the req.session.cart property holds an object of the Cart class.

However, when loading from the session in the second action (router.get('/overview') the req.session.cart property holds an object of no special class.

I assume/understand that JavaScript cannot know during deserialization what kind of object this JSON once has been. But how do other people solve this issue ?

I have been checking out other session middlewares (I currently use express-session), but none of them mention in detail, whether they are able to do what I am looking for.

Please help me understand and resolve this issue :)

Thanks everyone!

1 Answers

I assume/understand that JavaScript cannot know during deserialization what kind of object this JSON once has been.

You are right, the property value in req.session would be serialized as JSON by store (check express-session document), and the default serialization/deserialization of JavaScript (JSON.stringify and JSON.parse) does not recognize Class/Type information, that is the root cause of this problem. It is a general issue on JavaScript serialization.

To solve this general issue and retain Class/Type information during JavaScript serialization/deserialization, I've made an npm module named esserializer. It is pretty easy to sovle this Cart/CartItem problem with esserializer:

For GET /create interface, you can serialize req.session.cart with esserializer:

const ESSerializer = require('esserializer');
const Cart = require('./Cart');
const CartItem = require('./CartItem');

router.get('/create', function (req, res, next) {
    req.session.cart = new Cart();
    req.session.cart.addItem(new CartItem('Red Sox', 15, Math.round(Math.random() * 5)));

    res.render('cart/create.twig', {
        cart: ESSerializer.serialize(req.session.cart)
    });
});

Once we want to reconstruct this Cart object, with CartItem inside, just invoke the deserialize method of esserializer, and pass all related Classes as parameter:

const ESSerializer = require('esserializer');
const Cart = require('./Cart');
const CartItem = require('./CartItem');

router.get('/overview', function (req, res, next) {
    const cartInstance = ESSerializer.deserialize(serializedString, [Cart, CartItem]);
    console.log(cartInstance);
    //...
});

This reconstructed cartInstance object has all Class/Type information retained, including instance methods, if any.

Related