Closed tensor-programming closed 6 years ago
Never mind, figured it out right after I posted this.
Sorry - could you enlighten me with your fix? I'm debugging a piece of code that worked a few days ago :sob:
Ok, for anyone who has this issue it was in my case a problem that RabbitMQ was connected on 'amqp://localhost', after changing to 'amqp://localhost:5762' everything seems to work as expected
@tensor-programming I came out with the same problem like you. How did you fix it ?
@clouds8 - in my case it seemed to be a Firefox issue. It went away with a Firefox-update or when I used Chrome.
@gforge thx for reply. I find the point why I got stuck.
It seems that apollo-server do not support more than one subscription. I mean use installSubscriptionHandlers twice or more in one express service, because I generate two instances of ApolloServer and both of them use installSubscriptionHandlers method. It causes the error "Could not connect to websocket endpoint ws://127.0.0.1:4000/xxx. Please check if the endpoint url is correct.".
@clouds8 - two instances of ApolloServer sounds like a bad idea... Without knowing your motivation for this, I would consider looking into using Nginx to split the path into separate services.
I'm having the same issue. Changing browsers doesn't fix it, and it's only the one subscription. Any other tips?
Trying changing app.listen
to httpServer.listen
httpServer.listen({ port: PORT }, () => {
console.log(`server ready at http://localhost:${PORT}${apollo.graphqlPath}`)
console.log(`Subscriptions ready at ws://localhost:${PORT}${apollo.subscriptionsPath}`)
})
@tensor-programming could you please give a clarification on how you solved this issue?
Also, I think it's operating system specific. I'm using the same stack (apollo-server-express, etc..), and when I run the code on Ubuntu everything is working seamlessly, but when I run on Windows (I'm using Windows 10), I get the already mentioned error:
"Could not connect to websocket endpoint ws://localhost:6001/graphql. Please check if the endpoint url is correct."
Any help would be greatly appreciated
The following answer helped me solved it https://stackoverflow.com/questions/53415286/subscription-not-connecting-using-apolloserver
@tensor-programming could you please give a clarification on how you solved this issue?
Also, I think it's operating system specific. I'm using the same stack (apollo-server-express, etc..), and when I run the code on Ubuntu everything is working seamlessly, but when I run on Windows (I'm using Windows 10), I get the already mentioned error:
"Could not connect to websocket endpoint ws://localhost:6001/graphql. Please check if the endpoint url is correct."
Any help would be greatly appreciated
I'm having the same problem. I tested it on multiples machines within a LAN. The subscription is working fine in any Ubuntu browsers, but it is giving the error on Windows Browsers. At this moment, I only tested it using the playground tool, but I think the problem is somehow related to it. I think the playground tool have some bug on web socket connection from Windows browsers.
@LiveDuo @ardmont thanks for your replies!
I think it's definitely not a browser-specific issue in itself, but rather OS-specific as @ardmont also mentions. I haven't run subscriptions in production yet, so I don't know if it's playground specific, but anyhow this issue shouldn't be happening, and a clarification would be nice. Dockerizing the GraphQL server on windows (Using Linux containers) also doesn't make a difference. But when running it on a DigitalOcean Droplet (Ubuntu) it works.
Had the same issue, console was showing 400 error. Adding highlighted line from this article solved problem for me. https://www.apollographql.com/docs/apollo-server/data/subscriptions/#subscriptions-with-additional-middleware
@Hardronox your fix worked for me, thank you!
Tentando mudar
app.listen
parahttpServer.listen
igual a:
httpServer . listen ( { port : PORT } , ( ) => { console . log ( `servidor pronto em http: // localhost: $ { PORT } $ { apollo . graphqlPath } ` ) console . log ( `assinaturas prontas em ws: / / localhost: $ { PORT } $ { apollo . subscriptionsPath } ` ) } )
exatamente isso que estava faltando pro meu código funcionar ... kkk obrigado
Had the same issue, console was showing 400 error. Adding highlighted line from this article solved problem for me. https://www.apollographql.com/docs/apollo-server/data/subscriptions/#subscriptions-with-additional-middleware
@Hardronox how did you the link to the highlighted line? Also, thanks of the working solution.
I used this and it worked for me https://www.apollographql.com/docs/apollo-server/data/subscriptions/#subscriptions-with-additional-middleware
try replacing app.listen with httpServer.listen() and that worked for me
Please can you give a clear description of this problem so ill know exactly how the expected behavior is meant to be?
`import "reflect-metadata"; import { ApolloServer } from "apollo-server-express"; import http from 'http'; import Express from "express"; import session from "express-session"; import { createConnection } from "typeorm"; import { redis } from "./redis"; import connectRedis from "connect-redis"; import cors from "cors"; import { createShema } from './utils/createShema.utils'; import { environment } from './config/constant.config/enviroment.config'; import routes from "./route/index.route"; import { logger } from "./config/constant.config/logging.config.log"; import { indexing } from "./utils/elk/api/api.elastic.index"; import { AcessControlHeader, ElasticOrigin } from './config/constant.config/response.config'; import { requestPlugin } from "./utils/plugin/logger.plugin"; import { fieldExtensionsEstimator, getComplexity, simpleEstimator } from "graphql-query-complexity";
async function bootstrap() { const schema: any = await createShema() const app = Express() const httpServer = http.createServer(app) const RedisStore = connectRedis(session)
const apolloServer = new ApolloServer({
schema,
context: ({ req, res }) => ({ req, res }),
formatError: err => {
if (err.extensions)
logger.debug("rupix-api-backend",
err.extensions) // put winston here
return err
},
engine: {
/ Other, existing engine
configuration should remain the same. /
generateClientInfo: ({ request }) => {
const headers = request.http?.headers && request.http.headers;
if (headers) {
return {
clientName: headers['apollographql-client-nuggets'],
clientVersion: headers['apollographql-client-version-0.0.1'],
};
} else {
return {
clientName: "Unknown Client",
clientVersion: "Unversioned",
};
}
},
},
plugins: [
requestPlugin,
{
requestDidStart: () => ({
didResolveOperation({ request, document }) {
/**
* This provides GraphQL query analysis to be able to react on complex queries to your GraphQL server.
* This can be used to protect your GraphQL servers against resource exhaustion and DoS attacks.
* More documentation can be found at https://github.com/ivome/graphql-query-complexity.
*/
const complexity = getComplexity({
// Our built schema
schema,
// To calculate query complexity properly,
// we have to check only the requested operation
// not the whole document that may contains multiple operations
operationName: request.operationName,
// The GraphQL query document
query: document,
// The variables for our GraphQL query
variables: request.variables,
// Add any number of estimators. The estimators are invoked in order, the first
// numeric value that is being returned by an estimator is used as the field complexity.
// If no estimator returns a value, an exception is raised.
estimators: [
// Using fieldExtensionsEstimator is mandatory to make it work with type-graphql.
fieldExtensionsEstimator(),
// Add more estimators here...
// This will assign each field a complexity of 1
// if no other estimator returned a value.
simpleEstimator({ defaultComplexity: 1 }),
],
});
// Here we can react to the calculated complexity,
// like compare it with max and throw error when the threshold is reached.
if (complexity > 20) {
logger.error(`Sorry, too complicated query! ${complexity} is over 20 that is the max allowed complexity.`)
throw new Error(
`Sorry, too complicated query! ${complexity} is over 20 that is the max allowed complexity.`,
);
}
// And here we can e.g. subtract the complexity point from hourly API calls limit.
},
}),
}
],
playground: true || Boolean(environment.apollo.playground),
tracing: environment.apollo.tracing
})
apolloServer.installSubscriptionHandlers(httpServer)
app.use("/", routes)
app.use((req, res, done) => { res.header( AcessControlHeader, ElasticOrigin ) // this section is to implement the logger part done(); })
// this config for cors is just the host i expect the frontend to be at it depends app.use( cors({ credentials: true, origin: process.env.CLIENT_URL || "*" //check the .env file for this i.e http://localhost:3000 }) );
app.use( session({ store: new RedisStore({ client: redis as any, host: environment.redis.host, //the host to the redis instance where session is stored port: environment.redis.port, ttl: environment.redis.ttl }), name: environment.session.name, secret: environment.session.secret, resave: environment.session.resave, saveUninitialized: environment.session.saveUninitialized, cookie: { httpOnly: environment.session.cookie.httpOnly, secure: environment.session.cookie.secure, maxAge: environment.session.cookie.maxAge // 24 hours } }) );
apolloServer.applyMiddleware({ app, bodyParserConfig: true, cors: true, // path: environment.apollo.endpoint })
createConnection().then(() => {
httpServer.listen(environment.port, async () => {
logger.info(Server started, 🚀 listening on port ${environment.port} for incoming requests.Subscriptions ready at ws://localhost:${environment.port}${apolloServer.subscriptionsPath}
);
})
}).catch((err) => {
logger.info("Couldn't connect to the database.", err);
throw new Error(Couldn't connect to the database. ${err}
);
});
}
bootstrap(); `
`import "reflect-metadata"; import { ApolloServer } from "apollo-server-express"; import http from 'http'; import Express from "express"; import session from "express-session"; import { createConnection } from "typeorm"; import { redis } from "./redis"; import connectRedis from "connect-redis"; import cors from "cors"; import { createShema } from './utils/createShema.utils'; import { environment } from './config/constant.config/enviroment.config'; import routes from "./route/index.route"; import { logger } from "./config/constant.config/logging.config.log"; import { indexing } from "./utils/elk/api/api.elastic.index"; import { AcessControlHeader, ElasticOrigin } from './config/constant.config/response.config'; import { requestPlugin } from "./utils/plugin/logger.plugin"; import { fieldExtensionsEstimator, getComplexity, simpleEstimator } from "graphql-query-complexity";
async function bootstrap() { const schema: any = await createShema() const app = Express() const httpServer = http.createServer(app) const RedisStore = connectRedis(session)
const apolloServer = new ApolloServer({ schema, context: ({ req, res }) => ({ req, res }), formatError: err => { if (err.extensions) logger.debug("rupix-api-backend", err.extensions) // put winston here return err }, engine: { / Other, existing
engine
configuration should remain the same. /generateClientInfo: ({ request }) => { const headers = request.http?.headers && request.http.headers; if (headers) { return { clientName: headers['apollographql-client-nuggets'], clientVersion: headers['apollographql-client-version-0.0.1'], }; } else { return { clientName: "Unknown Client", clientVersion: "Unversioned", }; } }, }, plugins: [ requestPlugin, { requestDidStart: () => ({ didResolveOperation({ request, document }) { /** * This provides GraphQL query analysis to be able to react on complex queries to your GraphQL server. * This can be used to protect your GraphQL servers against resource exhaustion and DoS attacks. * More documentation can be found at https://github.com/ivome/graphql-query-complexity. */ const complexity = getComplexity({ // Our built schema schema, // To calculate query complexity properly, // we have to check only the requested operation // not the whole document that may contains multiple operations operationName: request.operationName, // The GraphQL query document query: document, // The variables for our GraphQL query variables: request.variables, // Add any number of estimators. The estimators are invoked in order, the first // numeric value that is being returned by an estimator is used as the field complexity. // If no estimator returns a value, an exception is raised. estimators: [ // Using fieldExtensionsEstimator is mandatory to make it work with type-graphql. fieldExtensionsEstimator(), // Add more estimators here... // This will assign each field a complexity of 1 // if no other estimator returned a value. simpleEstimator({ defaultComplexity: 1 }), ], }); // Here we can react to the calculated complexity, // like compare it with max and throw error when the threshold is reached. if (complexity > 20) { logger.error(`Sorry, too complicated query! ${complexity} is over 20 that is the max allowed complexity.`) throw new Error( `Sorry, too complicated query! ${complexity} is over 20 that is the max allowed complexity.`, ); } // And here we can e.g. subtract the complexity point from hourly API calls limit. }, }), } ], playground: true || Boolean(environment.apollo.playground), tracing: environment.apollo.tracing
})
apolloServer.installSubscriptionHandlers(httpServer)
app.use("/", routes)
app.use((req, res, done) => { res.header( AcessControlHeader, ElasticOrigin ) // this section is to implement the logger part done(); })
// this config for cors is just the host i expect the frontend to be at it depends app.use( cors({ credentials: true, origin: process.env.CLIENT_URL || "*" //check the .env file for this i.e http://localhost:3000 }) );
app.use( session({ store: new RedisStore({ client: redis as any, host: environment.redis.host, //the host to the redis instance where session is stored port: environment.redis.port, ttl: environment.redis.ttl }), name: environment.session.name, secret: environment.session.secret, resave: environment.session.resave, saveUninitialized: environment.session.saveUninitialized, cookie: { httpOnly: environment.session.cookie.httpOnly, secure: environment.session.cookie.secure, maxAge: environment.session.cookie.maxAge // 24 hours } }) );
apolloServer.applyMiddleware({ app, bodyParserConfig: true, cors: true, // path: environment.apollo.endpoint })
createConnection().then(() => { httpServer.listen(environment.port, async () => { logger.info(
Server started, 🚀 listening on port ${environment.port} for incoming requests.Subscriptions ready at ws://localhost:${environment.port}${apolloServer.subscriptionsPath}
); }) }).catch((err) => { logger.info("Couldn't connect to the database.", err); throw new Error(Couldn't connect to the database. ${err}
); });}
bootstrap(); `
check the highlighted bold code snippet to see how i used the http module and passed it inside my apply middleware .Bear in mind here that am using typegraphql but this should not be too far from what you have
@jeff-ofobrukweta Your fix works! Thanks
yes. add apolloServer.installSubscriptionHandlers(httpServer)
to your code
Writing a simple chat application using apollo and express. Prior to this I was using subscriptions-transport-ws and graphql-server-express but there was an issue with graphiql not being able to call subscriptions due to a client error with graphiql. Because of this issue, I swapped over to apollo.
Currently, when I try to access a subscription through graphiql the client comes back and says:
"Could not connect to websocket endpoint ws://localhost:6001/graphql. Please check if the endpoint url is correct."
If I try to use a simple websocket client to find the websocket endpoint, it doesn't seem to exist.I stripped out most of the stuff from my server/index.js file to see if I could solve this problem, heres what it looks like:
My imports in package.json look like this:
Not really sure why the subscription endpoint isn't properly being deployed through the
apollo.installSubscriptionHandlers(httpServer)
command.