When does session property (express session data object) gets added to request object when using express-session middleware? - node.js

When I use express-session middleware, when does the session property in request object(request.session) gets available?
Does it always stay available since the beginning when the server starts? when no session is made (no login) then session data is empty but session property itself is always available on request object. Is is this case? OR
does session object gets attached to request only when someone logs in? and when no user is logged in then request.session is always undefined . is it this?
The intention of this question is to know which, in typescript, out of the follow two type definition I have to use:
(one is using session? and in another session is used)
import { SessionData } from "express-session";
declare module "express-session" {
interface SessionData {
userId: string;
}
}
export interface MyContext {
session: SessionData;
}
OR
import { SessionData } from "express-session";
declare module "express-session" {
interface SessionData {
userId: string;
}
}
export interface MyContext {
session?: SessionData;
}

After long waiting I got the answer in Ben Awad discord channel.
Here it is
Session middleware is always defined, if no session exists on the request it'll return an empty object.
So the option-1 type definition is right, i.e.,
import { SessionData } from "express-session";
declare module "express-session" {
interface SessionData {
userId: string;
}
}
export interface MyContext {
session: SessionData;
}

Related

Problem with instance of class while creating reusable controller in node.js

I want to reuse all my servise and controllers and I was achieving this with extending class.
I'm calling the class of Controller and service all the way up from a router.
everything looks fine while creating instance of class,
but when I send request to sign in route it says there is no this.servise or this.dto which is i passed to the constructor while creating this instance of object
import express from "express";
const router = express.Router();
import UserController from "../../controllers/user.controller";
import UserService from "../../services/user.service.js";
import {UserDto} from "../../dtos/user.dto.js";
import User from "../../models/User.js";
const userService = new UserService(User);
console.log(userService, UserDto); // successfully logged
const userController = new UserController(userService, UserDto);
console.log(userController); // successfully logged
router.post('/signup', userController.signup);
router.post('/signin', userController.signIn);
router.post('/signout', userController.signOut);
router.get('/all', userController.getAll);
router.route("/:id")
.get(userController.get)
.post(userController.create)
.patch(userController.update)
.delete(userController.delete);
export default router;
export default class UserController extends MainController {
async signIn(req, res) {
try {
const {email, password} = req.body;//await this.dto.login(req.body);
const result = await this.service.signIn(email, password); // TypeError: Cannot read properties of undefined (reading 'service')
return res.status(201).json({message: "successfully signed in", token: result.token, user: this.dto.output(result.user)});
}
catch(err){
sendError(res, err);
}
}
I've reviewed my knowledge of how nodejs modules work, but I can't figure out what the problem is.
Who can explain me this situation, please!?
Thank you in advance!
You forgot to use .bind() when passing the references to the methods to the Express router. So who knows what the value of this will be when Express tries to call them (in JS, this doesn't work like other variable names, it doesn't use lexical scoping, what the value will be depends on the calling code).
Change your code to e.g.
router.post('/signup', userController.signup.bind(userController));
This will ensure that this is set to your userController object when the function gets called (bind() is a method available on all function objects that returns a new function with a fixed this value).

Nest js getting session data from the memory store

I was wondering if there is a method to access directly the session memory store and get the session data for a particular session id i'm using express-session package with the nest js freamwork.
Hope you found answers to your question since then. I came up with the following technique which is using NestJS DI system.
Background
According to NestJS official session documentation you can register a session middleware inside your main.ts file.
According to ExpressJS official session middleware documentation (the session(options) on top of the page), you can specify the session store that will be used by the middleware. If its omitted then the default MemoryStore is used.
All the session stores shares a common interface, so its a interchangeable part of your application, which makes a good candidate them to be provided as an injection token by a module. See a list of session stores advised by expressjs.
Implementation details
Create a new module (e.g. SessionModule), then add it to the imports array in your AppModule.
Next we create the injection token for the session store.
import { MemoryStore } from 'express-session';
import { SESSION_STORE } from './session.const';
#Module({
providers: [
{
provide: SESSION_STORE,
useFactory: () => {
return new MemoryStore();
},
},
],
exports: [SESSION_STORE],
})
export class SessionModule {}
where session.const.ts contains a simple export statement
export const SESSION_STORE = 'SESSION_STORE';
Now inside main.ts file, you can get a reference to the session store to setup session middleware.
const store = app.get(SESSION_STORE)
app.use(express.session({
store,
// ... other options
}
));
If you want to access sessionStore in other services / controllers you have to import the SessionModule to the module that declares them.
ex.
#Module({
imports: [SessionModule],
controllers: [UserController]
})
export class UserModule {}
// inside user controller you can inject a reference
// to the session store in the constructor
#Controller('user')
export class UserController {
constructor(#Inject(SESSION_STORE) private sessionStore) {}
}
With the sessionStore property you can get any stored session with the following method documented in the linked expressjs documentation. store.get(sid, callback)

Cannot set property 'userId' of undefined in session variable

Cannot read set property of 'userId' of undefined is a classic error that has been experienced in Express frameworks and documentation here covers what to do about it, but how do you resolve this issue in a NestJS application?
When you get an error message that says Cannot set property 'userId' of undefined you want to look at what is going on with your cookie-session.
Do you have a cookie-session installed?
The error is being thrown whenever you try to set the user id property on the users' session object, because that cookie middleware is not installed or it's not running, you get undefined.
So when you try to set a property on undefined, you get this classic error message.
So your cookie-session may not be set up.
Enough answers were given in a plain ExpressJS API, but what if you are working with NestJS? Well, here is the NestJS way to resolve this.
Import the following to your app.module.ts file:
import { Module, ValidationPipe } from '#nestjs/common';
import { APP_PIPE } from '#nestjs/core';
Go down to your list of providers and inside the array and a brand new object:
providers: [
AppService,
{
provide: APP_PIPE,
useValue: new ValidationPipe({
whitelist: true,
}),
},
],
So what does this really do? It says whenever we create an instance of the app module, automatically make use of it. Apply it to every incoming request that flows to the application, run it through the instance of a class. That's how to set up a global pipe, but you have to set up the cookie session middleware into a global middleware.
You need to import the following to the same file:
import { MiddlewareConsumer, Module, ValidationPipe } from '#nestjs/common';
At the bottom, add the following:
export class AppModule {
configure(consumer: MiddlewareConsumer) {}
}
The configure function gets called automatically whenever the application starts listening for incoming traffic. So inside of here I can set up some middleware that will run on every single incoming request.
To do, we call or reference consumer.apply() like so:
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(
cookieSession({
keys: ['dfghjkl'],
}),
);
}
}
I then need to ensure I add in a require statement for cookie session at the top:
const cookieSession = require('cookie-session');
And at the bottom also add:
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(
cookieSession({
keys: ['dfghjkl'],
}),
)
.forRoutes('*');
}
}
That means that I want to make use of the middleware on every single incoming request that comes into the application. That should be it.

Augmenting existing interfaces

This isn't a specific koa question even though all the code is using koa, I'm just new to node and the module system.
When using Koa every request is defined by the Request interface:
declare module "koa" {
namespace Koa {
...
export interface Request {
...
}
...
}
...
namespace Koa {}
export = Koa;
}
I'm using the bodyparser middleware so Request has a property named body but typescript is unaware of this and so I'm trying to add that by adding this definition file as a reference:
/// <reference path="globals/koa/index.d.ts" />
/// <reference path="koa.d.ts" />
import koa = require("koa");
...
app.use(ctx => {
console.log(ctx.request.body); // error: Property 'body' does not exist on type 'Request'
});
Where koa.d.ts is:
declare module "koa" {
namespace Koa {
export interface Request {
body: any;
}
}
export default Koa;
}
But this is probably the wrong way to do it as it's not working.
How can it be done?
Thanks.
I just had to work through this. I added this to my custom-typings.d.ts:
import {Request} from "koa";
declare module "koa" {
interface Request {
body: any;
}
}
Just ran into this. I found that since I was using koa-bodyparser middleware, I needed to install the #types/koa-bodyparser module which augments the interface for you - https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/koa-bodyparser/index.d.ts#L20.
import * as bodyparser from 'koa-bodyparser';
...
app.use(bodyParser());
Then, in your route, "body" will be available on the request object.
ctx.request.body

extending express application interface

I am trying to extend the expressjs Application interface using declaration merging as explained in the express type definitions
declare module Express {
// These open interfaces may be extended in an application-specific manner via declaration merging.
// See for example method-override.d.ts (https://github.com/borisyankov/DefinitelyTyped/blob/master/method-override/method-override.d.ts)
export interface Request { }
export interface Response { }
export interface Application { }
}
So, my app.ts looks like this:
/// <reference path="typings/express/express.d.ts" />
declare module Express {
export interface Application {
testA: string;
}
export interface Request {
testR: string;
}
}
import express = require('express');
var app = express();
app.testA = "why not?";
app.use(function (req, res, next) {
req.testR = "xxx";
})
I get the errors:
"Property testA does not exist on type Express"
"Property testR does not exist on type Request"
Any clues?
Since you are using modules, declaration merging won't happen here. In app.ts there isn't an Express module to merge with so it's making a completely separate module definition. You need to move the code...
declare module Express {
export interface Application {
testA: string;
}
export interface Request {
testR: string;
}
}
...into a .d.ts file so that the interfaces are merged with the ones in express.d.ts.

Resources