'NodeJs, Apollo, and typescript server hang on session storage
I'm new to NodeJs, and I'm following the full-stack tutorial made by Ben Awad https://www.youtube.com/watch?v=I6ypD7qv3Z8&t=7186s.
After setting up my server and everything works fine. I added express-session for session storage and linked it with Redis using Redis-connect and Redis client.
This is my index.ts:
import { MikroORM } from "@mikro-orm/core";
import { ApolloServer } from "apollo-server-express";
import connectRedis from "connect-redis";
import express from "express";
import session from "express-session";
import { createClient } from "redis";
import "reflect-metadata";
import { buildSchema } from "type-graphql";
import { __prod__ } from "./constants";
import mikroOrmConfig from "./mikro-orm.config";
import { PostResolver } from "./resolvers/post";
import { UserResolver } from "./resolvers/user";
import { MyContext } from "./types";
const main = async () => {
const orm = await MikroORM.init(mikroOrmConfig);
await orm.getMigrator().up();
const app = express();
const RedisStore = connectRedis(session);
const redisClient = createClient();
await redisClient.connect();
await redisClient.ping();
redisClient.on("error", err => console.log("Redis Client Error", err));
app.use(
session({
name: "qid",
store: new RedisStore({ client: redisClient, disableTouch: true }),
secret: "qsfniuiqsdnigu",
saveUninitialized: false,
resave: false,
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10,
httpOnly: true,
sameSite: "lax",
secure: __prod__,
},
})
);
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [UserResolver, PostResolver],
validate: false,
}),
context: ({ req, res }): MyContext => ({ em: orm.em, req, res }),
});
await apolloServer.start();
apolloServer.applyMiddleware({ app });
app.listen(4000, () => {
console.log(`listening on http://localhost:${4000}`);
});
};
main().catch(err => console.error("Errors: ", err));
And my types.ts file:
import { Connection, EntityManager, IDatabaseDriver } from "@mikro-orm/core";
import { Request, Response } from "express";
declare module "express-session" {
interface Session {
userId: number;
}
}
export type MyContext = {
em: EntityManager<IDatabaseDriver<Connection>>;
req: Request;
res: Response;
};
export type FieldError = {
errors: [
{
field: string;
message: string;
}
];
};
And my user.ts resolver where I think the problem occurs in Login mutation:
import argon2 from "argon2";
import {
Arg,
Ctx,
Field,
InputType,
Mutation,
ObjectType,
Resolver,
} from "type-graphql";
import { User } from "../entities/User";
import { MyContext } from "../types";
@InputType()
class LoginInputs {
@Field()
username: string;
@Field()
password: string;
}
@ObjectType()
class FieldError {
@Field()
field: string;
@Field()
message: string;
}
@ObjectType()
class UserResponse {
@Field(() => [FieldError], { nullable: true })
errors?: FieldError[];
@Field(() => User, { nullable: true })
user?: User;
}
@Resolver()
export class UserResolver {
@Mutation(() => UserResponse)
async login(
@Arg("options") options: LoginInputs,
@Ctx() { em, req }: MyContext
): Promise<UserResponse> {
const { username, password } = options;
const user = await em.findOne(User, { username });
const errors = {
errors: [
{
field: "username or password",
message: "There is no user with the given credentials",
},
],
};
if (!user) {
return errors;
}
const valid = await argon2.verify(user.password, password);
if (!valid) {
return errors;
}
req.session.userId = user.id; // If I comment this line everything works fine
return { user };
}
}
I'm using Node LTS (16.13.1 for now), and this is package.json:
{
"name": "lirredit-backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"watch": "tsc -w",
"dev": "nodemon dist/index.js",
"start": "node dist/index.js",
"create:migration": "mikro-orm migration:create"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/connect-redis": "^0.0.18",
"@types/express": "^4.17.13",
"@types/express-session": "^1.17.4",
"@types/node": "^17.0.14",
"nodemon": "^2.0.15",
"ts-node": "^10.4.0",
"typescript": "^4.5.5"
},
"dependencies": {
"@mikro-orm/cli": "^4.5.10",
"@mikro-orm/core": "^4.5.10",
"@mikro-orm/migrations": "^4.5.10",
"@mikro-orm/postgresql": "^4.5.10",
"apollo-server-core": "^3.6.2",
"apollo-server-express": "^3.6.2",
"argon2": "^0.28.4",
"class-validator": "^0.13.2",
"connect-redis": "^6.0.0",
"cors": "^2.8.5",
"express": "^4.17.2",
"express-session": "^1.17.2",
"graphql": "15.7.2",
"pg": "^8.7.1",
"redis": "^4.0.3",
"reflect-metadata": "^0.1.13",
"type-graphql": "^1.1.1"
},
"mikro-orm": {
"useTsNode": true,
"configPaths": [
"./src/mikro-orm.config.ts",
"./dist/mikro-orm.config.js"
]
}
}
After making a request to localhost:4000/graphql and calling the Login mutation the request hangs and if I tried to refresh the page the client could not connect to localhost:4000/graphql until I delete the cookies cache.
I've tried it in Chrome with two accounts, Firefox, Edge, Apollo Studio, Thunder Client, and Postman; and all producing the same behavior.
It's worth noting that I'm am using WSL2 and Ubuntu distribution but I moved my project to Windows and the same problem persists.
Any help is really appreciated I'm new to Node and I've searched this issue for 4 days now before posting. Thanks.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
