So I am building a website with node.js, express, express-session, and sequelize.js. Once a user logs in, an instance of the Sequelize model User
is created. In my route for user log-in (/auth/login
), I have:
var user = (await User.findAll(
{where: {
username: username
}}))[0];
and I few lines down I assign that user
to the session.
req.session.user = user;
And then I can persist any changes by simply calling the save
method of req.session.user
:
await req.session.user.save();
And indeed, if I add this line next:
console.log(Object.getPrototypeOf(req.session.user));
the output is [object SequelizeInstance:User]
. So far so good.
In another route (/users/myaccount/edit-bio
) I am able to access the values of req.session.user
. That is, the output of
console.log(req.session.user.username);
is seanletendre
, as expected. But now when I call
await req.session.user.save();
all I get is the error message:
UnhandledPromiseRejectionWarning: TypeError: req.session.user.save is not a function
"That is weird," I thought, "isn't this the same object?" To investigate, I add the line:
console.log(Object.getPrototypeOf(req.session.user));
just as I did in the log-in route. And what is the output? It is: [object Object]
. So it seems that somehow the prototype of req.session.user
gets forgotten. I don't understand how this can be.
Is it possible to re-assign a prototype to a plain object?
Based on the comments to my question, I suspect that the prototype is lost when the session manager serializes req.session
. It seems that, unlike I thought before,req.session
does not point to the exact same session
object for different requests. Each time a request ends, it serializes and stores req.session
. Then upon receiving a new request with a cookie designating it as part of the same session, the session
object is fetch from the session store.
This is how my session middleware is setup:
var session = require('express-session');
//
// yada, yada, yada
//
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {secure: true}
}));
So what surprises me is that, even though I am using the default store MemoryStore
, my sessions are still serialized.
My question now becomes: how can I prevent object serialization upon session store when using MemoryStore
?
The Object. getPrototypeOf() method returns the prototype (i.e. the value of the internal [[Prototype]] property) of the specified object.
Every object in JavaScript has a built-in property, which is called its prototype. The prototype is itself an object, so the prototype will have its own prototype, making what's called a prototype chain.
We can access the function's prototype property using functionName. prototype . As seen from the above image prototype property of the function is an object (prototype object) with two properties: constructor property which points to Human function itself.
In express-session the method save()
is exposed by the object session
into the request
object (docs), eg.:
req.session.save(callback)
Your code req.session.user.save()
is wrong, the correct way is req.session.save()
, diff.:
req.session.user.save();
-----------^^^^^
req.session.save()
The method save()
isn't a Promise
, you must pass a callback for wait for the result of the save:
req.session.user = user;
req.session.save(function(err) {
if( err ){
// session not saved
} else {
// session saved
}
})
you can transform it into a Promise
(and await it), in this way:
const saveSession = (req) => {
return new Promise((resolve, reject) => {
req.session.save(function(err) {
if( err ){
reject(err);
} else {
resolve(true);
}
});
});
};
req.session.user = user;
await saveSession(req);
The method save()
is automatically called at the end of the HTTP response if the session data has been altered. Because of this, typically this method does not need to be called.
UPDATE
I call req.session.user.save() because I want to save the Sequelize Model instance into my database.
express-session use JSON.stringify()
for serialize the session into a string and store into a session storage (more info). JSON.stringify()
doesn't understand functions and only property are stored. For this reason, your save()
function is lost.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With