Undefined session object with apollo v4 express and express-session
ElectronicBeef opened this issue · comments
For the backend in my fullstack application I'm using ApolloGraphQL 4.0 with Express. I can succesfully use my resolvers (TypeOrm with TypeGraphql) to write and retrieve data from my database (PostgreSQL).
I'm using express-session with the connect-redis package to handle sessions and set a cookie for my register resolver, but when trying to store data in the session object, I get the following error message regarding my session object:
TypeError: Cannot read properties of undefined (reading 'session')
And no cookie is set.
I've tried different versions of the connect-redis package, i've tried changing the order of my different middlewares and more but whatever I do I get the same error and no cookie is set. This is my index.ts:
import "reflect-metadata";
import AppDataSource from "./data-source";
import { ApolloServer } from "@apollo/server";
import { expressMiddleware } from "@apollo/server/express4";
import { ApolloServerPluginDrainHttpServer } from "@apollo/server/plugin/drainHttpServer";
import express, { Request, Response } from "express";
import http from "http";
import cors from "cors";
import { json } from "body-parser";
import { Hello } from "./resolvers/hello";
import { UserResolver } from "./resolvers/user";
import { buildSchema } from "type-graphql";
import RedisStore from "connect-redis";
import session from "express-session";
import { createClient } from "redis";
export type MyContext = {
req: Request & { session: Express.Session };
res: Response;
};
const main = async () => {
await AppDataSource.initialize();
const app = express();
app.set("trust proxy", 1);
app.set(
"Access-Control-Allow-Origin",
"https://sandbox.embed.apollographql.com"
);
app.set("Access-Control-Allow-Credentials", true);
const httpServer = http.createServer(app);
const port = 3000;
const corsOptions = {
origin: "https://sandbox.embed.apollographql.com",
credentials: true,
};
const redisClient = createClient();
redisClient.connect().catch(console.error);
const redisStore = new RedisStore({
client: redisClient,
prefix: "myapp:",
});
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [Hello, UserResolver],
}),
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});
await apolloServer.start();
app.use(
session({
name: "qid",
store: redisStore,
resave: false,
saveUninitialized: false,
secret: "weotjweptoijwepitn",
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10,
httpOnly: true,
sameSite: "none",
secure: true,
},
}),
cors(corsOptions),
json(),
expressMiddleware(apolloServer, {
context: async ({ req, res }) => ({ req, res }),
})
);
httpServer.listen(port, () => {
console.log(`Server now running on port: ${port}`);
});
};
main();
And this is my userResolver.ts:
import { Resolver, Mutation, Arg, Query, Ctx } from "type-graphql";
import User from "../entities/User";
import { MyContext } from "../index";
@Resolver()
export class UserResolver {
@Mutation(() => User)
async register(
@Arg("username") username: string,
@Arg("password") password: string,
@Arg("email") email: string,
@Ctx("req") { req }: MyContext,
): Promise<User> {
const user = await User.create({
username,
email,
password,
}).save();
try {
req.session.userId = user.id;
}
catch (error) {
console.log(error);
console.error(error);
}
return user;
}
@Query(() => [User])
async findAllUsers(): Promise<User[]> {
const Users = await User.find({
select: {
id: true,
username: true,
email: true,
},
});
return Users;
}
}
Closing it, got the fix here: tj/connect-redis#383