I wanted to add subscription to my already working apollo server with express but I cannot connect even with the playground. I get this error from the playground
"error": "Could not connect to websocket endpoint ws://localhost:4000/graphql. Please check if the endpoint url is correct."
From firefox an chrome I get similar errors
Firefox canβt establish a connection to the server at ws://localhost:4000/graphql
This is my app.js my main file.
const express = require('express');
const mongoose = require('mongoose');
const { ApolloServer } = require('apollo-server-express');
const cors = require('cors');
const session = require('express-session');
const Keycloak = require('keycloak-connect');
const { typeDefs } = require('./graphql/Schema');
const { resolvers } = require('./graphql/Resolvers');
const { userTypeDefs, userResolvers } = require('./graphql/User');
const { campusTypeDefs, campusResolvers } = require('./graphql/Campus');
const { profileTypeDefs, profileResolvers } = require('./graphql/Profile');
const { notificationTypeDefs, notificationResolvers } = require('./graphql/Notification');
const { rideTypeDefs, rideResolvers } = require('./graphql/Ride');
const app = express();
app.use(i18n.init);
const keycloak = new Keycloak({
memoryStore
}, 'keycloak.json');
app.use('/graphql', keycloak.middleware());
const server = new ApolloServer({
typeDefs: [KeycloakTypeDefs, typeDefs, rideTypeDefs, userTypeDefs, campusTypeDefs, profileTypeDefs, notificationTypeDefs],
schemaDirectives: KeycloakSchemaDirectives,
cors: cors(corsOptions),
resolvers: [resolvers, rideResolvers, userResolvers, campusResolvers, profileResolvers, notificationResolvers],
context: ({ req, connection }) => {
console.log(connection);
return { kauth: new KeycloakContext({ req }) };
},
subscriptions: {
onConnect: async (connectionParams, webSocket) => {
console.log("xxx");
console.log(connectionParams);
if (connectionParams.authToken) {
return validateToken(connectionParams.authToken)
.then(findUser(connectionParams.authToken))
.then(user => {
return {
currentUser: user,
};
});
}
throw new Error('Missing auth token!');
},
}
});
server.applyMiddleware({ app });
server.installSubscriptionHandlers(app);
mongoose.connect(
'mongodb://deaventon:mapache@localhost:27017/deaventon')
.then(result => {
app.listen(4000);
})
.catch(err => console.log(err));
According to some example server.installSubscriptionHandlers should be enought, in some other cases they dont event use it. But I think it has to do with apollo-server-express, usually examples with apollo-server-express use that. When I do a console.log() to connection I get an undefined from that, even withrequest from socket connections. I can see the req or socket request. I never get anything in the subscription.onConnect function, it is not being called apparently because It never stablishes a connection. If I do console.log from context to the req var I get something like this
IncomingMessage {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: null,
ended: true,
endEmitted: false,
reading: false,
sync: true,
needReadable: false,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
emitClose: true,
autoDestroy: false,
destroyed: false,
defaultEncoding: 'utf8',
awaitDrain: 0,
readingMore: true,
decoder: null,
encoding: null,
[Symbol(kPaused)]: null
},
readable: true,
_events: [Object: null prototype] {
end: [Function: resetHeadersTimeoutOnReqEnd]
},
_eventsCount: 1,
_maxListeners: undefined,
socket: Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: null,
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: true,
It seems like it is no even validating the subscriptions.
You have to pass another http server to installSubscriptionHandlers NOT the express one and listen on it. Here is your code simplified and working:
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const { gql } = require('apollo-server');
const http = require('http');
const app = express();
/* I have removed your middleware to simplify example
but you can observe that middleware is still used */
app.use(function (req, res, next) {
console.log('Time:', Date.now())
next()
});
const resolvers = {
Query: { test: () => {} },
Subscription: { test: () => {} },
Mutation: { test: () => {} },
};
const typeDefs = gql`
type Query {
test(id: ID!): ID
}
type Mutation {
test(id: ID!): ID
}
type Subscription {
test(id: ID!): ID
}
`;
const server = new ApolloServer({
typeDefs: [typeDefs],
resolvers: [resolvers],
context: ({ req, connection }) => {
console.log(connection);
return {};
},
subscriptions: {
onConnect: async (connectionParams, webSocket) => {
console.log('xxx');
console.log(connectionParams);
},
},
});
const httpServer = http.createServer(app);
server.applyMiddleware({ app });
server.installSubscriptionHandlers(httpServer);
const port = 4003;
httpServer.listen(port, () => {
console.log(
`π Server ready at http://localhost:${port}${server.graphqlPath}`,
);
console.log(
`π Subscriptions ready at ws://localhost:${port}${server.subscriptionsPath}`,
);
});
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