I am trying to implement a GraphQL subscription server using the SubscriptionServer from the ‘subscriptions-transport-ws’ library. My problem is that the context object, which is passed to the subscription server, is not available inside the subscription.
`this my surver.js
import mongoose from 'mongoose';
import express from 'express';
import helmet from 'helmet';
import favicon from 'serve-favicon';
import path from 'path';
import { fileURLToPath } from 'url';
import cors from 'cors';
import {
ApolloServerPluginLandingPageGraphQLPlayground,
ApolloServerPluginLandingPageDisabled,
ApolloServerPluginDrainHttpServer
} from 'apollo-server-core';
import { ApolloServer } from 'apollo-server-express';
import { UserInputError } from 'apollo-server-errors';
import { ENVIRONMENT } from './config/environment.js';
import { environmentVariablesConfig } from './config/appConfig.js';
import { logger, endLogger } from './helpers/logger.js';
import { requestDevLogger } from './helpers/requestDevLogger.js';
import { setContext } from './gql/auth/setContext.js';
import { initTypeDefinition } from './gql/types/index.js';
import { resolvers } from './gql/resolvers/index.js';
import { getListOfIPV4Address } from './helpers/getListOfIPV4Address.js';
import routesManager from './routes/routesManager.js';
import { createServer } from 'http';
import { execute, subscribe } from 'graphql';
import { SubscriptionServer } from 'subscriptions-transport-ws';
import { makeExecutableSchema } from '@graphql-tools/schema';
import createSubscriptionServer from './helpers/createSubscriptionServer.js';
import formatError from './helpers/formatError.js';
if (
environmentVariablesConfig.formatConnection === 'DNSseedlist' &&
environmentVariablesConfig.mongoDNSseedlist !== ''
) {
mongoose.connect(environmentVariablesConfig.mongoDNSseedlist);
} else {
if (environmentVariablesConfig.mongoUser !== '' && environmentVariablesConfig.mongoPass !== '') {
mongoose.connect(
`mongodb://${environmentVariablesConfig.mongoUser}:${environmentVariablesConfig.mongoPass}@${environmentVariablesConfig.dbHost}:${environmentVariablesConfig.dbPort}/${environmentVariablesConfig.database}`
);
} else {
mongoose.connect(
`mongodb://${environmentVariablesConfig.dbHost}:${environmentVariablesConfig.dbPort}/${environmentVariablesConfig.database}`
);
}
}
const db = mongoose.connection;
db.on('error', (err) => {
logger.error(`Connection error with database. ${err}`);
});
db.once('open', () => {
if (environmentVariablesConfig.environment !== ENVIRONMENT.DEVELOPMENT) {
logger.info(`Connected with MongoDB service (${ENVIRONMENT.PRODUCTION} mode)`);
} else {
if (
environmentVariablesConfig.formatConnection === 'DNSseedlist' &&
environmentVariablesConfig.mongoDNSseedlist !== ''
) {
logger.info(
`Connected with MongoDB service at "${environmentVariablesConfig.mongoDNSseedlist}" using database "${environmentVariablesConfig.database}" (${ENVIRONMENT.DEVELOPMENT} mode)`
);
} else {
logger.info(
`Connected with MongoDB service at "${environmentVariablesConfig.dbHost}" in port "${environmentVariablesConfig.dbPort}" using database "${environmentVariablesConfig.database}" (${ENVIRONMENT.DEVELOPMENT} mode)`
);
}
}
initApplication();
});
const initApplication = async () => {
const app = express();
const httpServer = createServer(app);
if (environmentVariablesConfig.environment === ENVIRONMENT.PRODUCTION) {
app.use(helmet());
} else {
// Allow GraphQL Playground on development environments
app.use(helmet({ contentSecurityPolicy: false, crossOriginEmbedderPolicy: false }));
}
app.use(cors({ credentials: true }));
const __dirname = path.dirname(fileURLToPath(import.meta.url));
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use('', routesManager);
const typeDefs = await initTypeDefinition();
const schema = makeExecutableSchema({ typeDefs, resolvers });
const server = new ApolloServer({
schema,
context: setContext,
formatError,
tracing: true,
introspection: environmentVariablesConfig.environment === ENVIRONMENT.PRODUCTION ? false : true, // Set to "true" only in development mode
plugins:
environmentVariablesConfig.environment === ENVIRONMENT.PRODUCTION
? [ApolloServerPluginLandingPageDisabled()]
: [requestDevLogger, ApolloServerPluginLandingPageGraphQLPlayground(), ApolloServerPluginDrainHttpServer({ httpServer })], // Log all querys and their responses. Show playground (do not use in production)
// formatError (error) {
// if (!(error.originalError instanceof UserInputError)) {
// logger.error(error.message);
// }
// return error;
// },
});
await server.start();
server.applyMiddleware({ app });
SubscriptionServer.create(
{ schema, execute, subscribe },
{ server: httpServer, path: server.graphqlPath }
);
// createSubscriptionServer({
// server: httpServer, // this attaches itself directly to the server
// schema,
// context: setContext,
// path: server.graphqlPath,
// });
app.use((req, res) => {
res.status(404).send('404'); // eslint-disable-line no-magic-numbers
});
httpServer.listen(environmentVariablesConfig.port, () => {
getListOfIPV4Address().forEach((ip) => {
logger.info(`Application running on: http://${ip}:${environmentVariablesConfig.port}`);
if (environmentVariablesConfig.environment !== ENVIRONMENT.PRODUCTION) {
logger.info(
`GraphQL Playground running on: http://${ip}:${environmentVariablesConfig.port}${server.graphqlPath}`
);
}
});
});
// Manage application shutdown
process.on('SIGINT', () => {
logger.info('Stopping application...');
endLogger();
process.exit();
});
};
resolver
Subscription: {
newUser: {
subscribe: (_, __, Context) => {
console.log('thisssss', Context);
return pubsub.asyncIterator('NUMBER_INCREMENTED');
}
}
}
types
import { gql } from 'apollo-server-express';
export default /* GraphQL */ gql`
type User {
email: String
isAdmin: Boolean
isActive: Boolean
uuid: String
registrationDate: String
lastLogin: String
}
type Query {
"""
Get list of all users registered on database
"""
listAllUsers: [User]
}
type Subscription {
newUser: String
}
`;
packages and versions
"dependencies": {
"@graphql-tools/load-files": "6.6.1",
"@graphql-tools/merge": "8.3.14",
"@graphql-tools/schema": "^9.0.14",
"apollo-server-express": "3.11.1",
"bcrypt": "5.1.0",
"cors": "2.8.5",
"dotenv": "16.0.3",
"editorconfig": "^1.0.1",
"express": "4.18.2",
"graphql": "16.6.0",
"graphql-subscriptions": "^2.0.0",
"helmet": "6.0.1",
"jsonwebtoken": "9.0.0",
"lodash.merge": "4.6.2",
"log4js": "6.7.1",
"mongoose": "6.8.1",
"serve-favicon": "2.5.0",
"subscriptions-transport-ws": "^0.11.0"
}
I have tried different approaches, but the context object is still not available inside the subscription. Can someone help me understand what I am doing wrong and how to fix this issue?