GraphQL with ApolloServer says "GET query missing." even though I have playground set to true the way another post advised - graphql

I am trying to use Postman to hit a graphQL endpoint to teach myself how it works. I have a database with user data prepopulated and two Postman routes that should work but don't work.
The requests I am trying to send via Postman:
(1) Using GraphQL mode under the Body tab
{
User {
first_name
last_name
}
}
(2) using the raw mode under the Body tab
{
user {
first_name
last_name
}
}
In both cases I have correctly set the headers Content-Type to application/graphql. So it's not that.
I found two posts about this while Googling. Both are on StackOverflow.
(1) apollo-server returning GET query missing when playground is disabled
This one says basically, "do this":
const server = new ApolloServer({
introspection: true, // i inserted this line & the next one as specified
playground: true,
typeDefs,
resolvers,
})
(2) GET query missing: Implementing GraphQL Using Apollo On an Express Server
This one references the prior link. It's also for graph-server-express, and I'm using apollo-server-fastify
I also found Apollo Graphql with Fastify who also has "GET query missing." issue but no solution. It says to downgrade to fastify v2 but that's an old answer from 2020. This is 2022, we can do better.
Again the issue is that Postman says "GET query missing." to all my requests.
My server:
async function startApolloServer(typeDefs, resolvers) {
const apolloServer = new ApolloServer({
// introspection: true,
// playground: true, // to resolve "GET query missing." in Postman
typeDefs,
resolvers,
plugins: [
fastifyAppClosePlugin(fastify),
ApolloServerPluginDrainHttpServer({ httpServer: fastify.server }),
ApolloServerPluginLandingPageGraphQLPlayground(),
],
context: ({ request, reply }) => {
//Invaluable for debugging
if (env === "development") {
console.log("GOT A REQUEST: ", request.body);
}
return { knex, reply };
},
});
await apolloServer.start();
fastify
.register(helmet)
.register(require("fastify-sensible"))
.register(require("fastify-healthcheck"))
.register(require("fastify-formbody"))
.register(apolloServer.createHandler());
await fastify.listen(serviceListeningPort);
console.log(
`🚀 Server ready at http://localhost:${serviceListeningPort}${apolloServer.graphqlPath}`
);
}
startApolloServer(typeDefs, resolvers);
Also, the updated version of Apollo Server seems to replace playground: true with ApolloServerPluginLandingPageGraphQLPlayground(), which for me enables a page that says "Loading GraphQL Playground" at the server root but never finishes loading.

Related

GET query missing: Apollo Client on nodejs server

I'm running an Apollo GraphQL Client on a nodejs server locally that interacts with a GraphQL endpoint hosted on the cloud. I'm getting a "GET query missing" error whenever I query that endpoint with the client, despite the fact that I also have an Angular application using Apollo Angular (which internally uses Apollo Client), which is able to successfully query the cloud endpoint. The client also works fine if I host the GraphQL endpoint locally on my machine. I'm also using the cross-fetch package as my polyfill for fetch.
Here's my code for making the GraphQL client:
public rebuildClient() {
if (this.apollo) {
this.apollo.stop();
this.apollo.clearStore();
}
this.apollo = new ApolloClient(this.configureApolloClientOptions());
}
private configureApolloClientOptions() {
const uploadLink = createUploadLink({
uri: this.serverConfig.httpsPrefix + this.serverConfig.backendDomain + this.serverConfig.graphqlRelativePath,
headers: { 'Apollo-Require-Preflight': 'true' },
fetch: fetch,
});
if (this.graphQLWsClient) this.graphQLWsClient.dispose();
this.graphQLWsClient = createClient({
url: this.serverConfig.wssPrefix + this.serverConfig.backendDomain + this.serverConfig.graphqlRelativePath,
connectionParams: {
authentication: `Basic-Root ${this.authConfig.backendRootUser.username}:${this.authConfig.backendRootUser.password}`,
},
webSocketImpl: WebSocket,
});
const webSocketLink = new GraphQLWsLink(this.graphQLWsClient);
// using the ability to split links, you can send data to each link
// depending on what kind of operation is being sent
const splitLink = split(
// split based on operation type
({ query }) => {
const definition = getMainDefinition(query);
return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
},
webSocketLink,
uploadLink,
);
return {
link: splitLink,
cache: new InMemoryCache(),
};
}
Here's a template for the serverConfig, which is a JSON file:
{
"backendDomain": "localhost:3000",
"cdnDomain": "localhost:3000",
"cdnHttpsPrefix": "http://",
"httpsPrefix": "http://",
"wssPrefix": "ws://",
"cdnRelativePath": "/cdn",
"dynamicCdnRelativePath": "/cdn/dynamic",
"graphqlRelativePath": "/graphql",
"selfHostedPrefix": "cdn://",
"archiveCategoryId": ""
}
Note that everything works if backendDomain is set to a localhost domain. But when I set it to an actual domain, the Apollo Client breaks with the errors mentioned above.

Cypress not seeing graphql request

This seems to be a long lasting issue:
In cypress interface, my application cannot send any graphql request or receive any response. Because it is fetch type.
here is the network status in cypress:
But in normal browser, I actually have several graphql requests, like here:
I know there are already quite several discussions and workarounds, such as using an polyfill to solve this problem such as below:
https://gist.github.com/yagudaev/2ad1ef4a21a2d1cfe0e7d96afc7170bc
Cypress does not intercept GraphQL API calls
but unfortunately, they are not working in my case.
Appreciate to the help of any kinds.
p.s.: I am using cypress 8.3.0, React as the front-end, and using apollo client and apollo server for all graphql stuff.
EDIT:
samele intercept:
cy.intercept('POST', Cypress.env('backendpiUrl') + '/graphql', req => {
if (req.body.operationName === 'updateItem') {
req.alias = 'updateItemMutation';
}
});
sample cypress console:
You can see that all the requests are XHR based, no graphql's fetch request
The links are old, unfetch polyfill is no longer necessary. Since the introduction of cy.intercept(), fetch is able to be waited on, stubbed etc.
Here's the docs Working with GraphQL and an interesting atricle Smart GraphQL Stubbing in Cypress (Note route2 is an early name for intercept)
More up-to-date, posted two days ago bahmutov - todo-graphql-example
Key helper function from this package:
import {
ApolloClient,
InMemoryCache,
HttpLink,
ApolloLink,
concat,
} from '#apollo/client'
// adding custom header with the GraphQL operation name
// https://www.apollographql.com/docs/react/networking/advanced-http-networking/
const operationNameLink = new ApolloLink((operation, forward) => {
operation.setContext(({ headers }) => ({
headers: {
'x-gql-operation-name': operation.operationName,
...headers,
},
}))
return forward(operation)
})
const httpLink = new HttpLink({ uri: 'http://localhost:3000' })
export const client = new ApolloClient({
link: concat(operationNameLink, httpLink),
fetchOptions: {
mode: 'no-cors',
},
cache: new InMemoryCache(),
})
Sample test
describe('GraphQL client', () => {
// make individual GraphQL calls using the app's own client
it('gets all todos (id, title)', () => {
const query = gql`
query listTodos {
# operation name
allTodos {
# fields to pick
id
title
}
}
`
cy.wrap(
client.query({
query,
}),
)
.its('data.allTodos')
.should('have.length.gte', 2)
.its('0')
.should('deep.equal', {
id: todos[0].id,
title: todos[0].title,
__typename: 'Todo',
})
})
Please show your test and the error (or failing intercept).

Getting NextAuth.js user session in Apollo Server context

My web app is using:
NextJS
NextAuth.js
Apollo Server
I have a NextAuth set up in my app, and I am able to log in just fine.
The problem is coming from trying to get access to the user's session in the Apollo context. I want to pass my user's session into every resolver. Here's my current code:
import { ApolloServer, AuthenticationError } from "apollo-server-micro";
import schema from "./schema";
import mongoose from "mongoose";
import dataloaders from "./dataloaders";
import { getSession } from "next-auth/client";
let db;
const apolloServer = new ApolloServer({
schema,
context: async ({ req }) => {
/*
...
database connection setup
...
*/
// get user's session
const userSession = await getSession({ req });
console.log("USER SESSION", userSession); // <-- userSession is ALWAYS null
if (!userSession) {
throw new AuthenticationError("User is not logged in.");
}
return { db, dataloaders, userSession };
},
});
export const config = {
api: {
bodyParser: false,
},
};
export default apolloServer.createHandler({ path: "/api/graphql" });
The problem is, the session (userSession) is always null, even if I am logged in (and can get a session just fine from a proper NextJS API route). My guess is that because the NextAuth function used to get the session, getSession({ req }) is being passed req--which is provided from Apollo Server Micro, and not from NextJS (which NextAuth is expecting). I've done a lot of searching and can't find anyone who's had this same problem. Any help is much appreciated!
I had exactly this issue and I found it was because of the Apollo GraphQL playground.
The playground does not send credentials without "request.credentials": "include".
My NextAuth / GraphQL API looks like this:
import { ApolloServer } from "apollo-server-micro";
import { getSession } from "next-auth/client";
import { typeDefs, resolvers } "./defined-elsewhere"
const apolloServer = new ApolloServer({
typeDefs,
resolvers,
context: async ({ req }) => {
const session = await getSession({ req });
return { session };
},
playground: {
settings: {
"editor.theme": "light",
"request.credentials": "include",
},
},
});
Hope this works for you!
I just ran into something similar. I'm not 100% sure because it's hard to know the exact details since your example code above doesn't show how you're interacting with apollo from the client before the session is coming through as null. I believe however that you're probably making an API call from inside the getStaticProps which causes static code generation and gets run at build time - ie when no such user context / session could possibly exist.
See https://github.com/nextauthjs/next-auth/issues/383
The getStaticProps method in Next.js is only for build time page generation (e.g. for generating static pages from a headless CMS) and cannot be used for user specific data such as sessions or CSRF Tokens.
Also fwiw I'm not sure why you got downvoted - seems like a legit question to ask imo even if the answer is mostly a standard rtm :). Has happened to me here before too - you win some you lose some :) Cheers

How to use Apollo-Gateway with swagger-to-graphql tool?

I'm using Swagger Petstore via swagger-to-graphql npm module and able to run the GraphQL Playground for it.
graphQLSchema('./swagger.json', 'http://petstore.swagger.io/v2', {
Authorization: 'Basic YWRkOmJhc2ljQXV0aA=='
}).then(schema => {
const app = express();
app.use('/', graphqlHTTP(() => {
return {
schema,
graphiql: true
};
}));
app.listen(4001, 'localhost', () => {
console.info('http://localhost:4001/');
});
}).catch(e => {
console.log(e);
});
However, when I tried to feed the service to Apollo Gateway, it throws Error: Apollo Server requires either an existing schema or typeDefs
const gateway = new ApolloGateway({
serviceList: [
{ name: 'pet', url: 'http://localhost:4001' }
],
});
const server = new ApolloServer({
gateway,
// Currently, subscriptions are enabled by default with Apollo Server, however,
// subscriptions are not compatible with the gateway. We hope to resolve this
// limitation in future versions of Apollo Server. Please reach out to us on
// https://spectrum.chat/apollo/apollo-server if this is critical to your adoption!
subscriptions: false,
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
What am I missing?
From the docs:
Converting an existing schema into a federated service is the first step in building a federated graph. To do this, we'll use the buildFederatedSchema() function from the #apollo/federation package.
You cannot provide just any existing service to the gateway -- the service must meet the federation spec. The only way to currently do that is to use buildFederatedSchema to create the service's schema. At this time, buildFederatedSchema does not accept existing schemas so federation is not compatible with any other tools that generate a schema for you. Hopefully that feature will be added in the near future.

Unsupported content type with GraphIql apollo engine

I'm running apollo-server-express, and all works fine. I have 2 endpoints - 1 for graphiql (/graphql) and one for non-interactive (/client) queries (I know - they were called that before I started with apollo).
app.use('/client', bodyParser.json() ,
(req, res,next) => {
const context = { pool , apiKey:req.query.key , bidules };
if (server.isAuthorized(context.apiKey)) {
return graphqlExpress({
schema: schema,
context: context,
tracing: true,
cacheControl: {
defaultMaxAge: 30,
}
}) (req,res,next);
}
else {
res.setHeader('Content-Type', 'application/json');
res.status(403)
.send (JSON.stringify({
errors:[ {message: "api key is unauthorized"} ]
}));
}
}
);
// endpoint for browser graphIQL
app.use('/graphql', graphiqlExpress({
endpointURL: '/client'
}));
app.use("/schema", (req, res) => {
res.set("Content-Type", "text/plain");
res.send(printSchema(schema));
});
But, when I introduce apollo engine
engine.listen({
port: port,
expressApp: fidserver.app,
graphqlPaths: ['/graphql', '/client']
});
everything still works fine - except when I refresh graphiql on the browser with the query as parameters on the browser url.
Then I get this error
{"errors":[{"message":"Unsupported Content-Type from origin: text/html"}]}
Doing the same thing without apollo engine running does not cause an error. If run the query again, or refresh the browser without the query and variable parameters everything works just fine with or without Apollo Engine enabled.
When the error happens I can see from my server log that it's trying to return a react web page containing some javascript for decoding parameters from somewhere but I can't track down from where - it doesn't get as far as hitting any of my code.
This was solved by the guys at Apollo. Here's the answer - I shouldn't have had my graphIQL end point mentioned in the engine.listen options.
Engine should only be placed between the client and the GraphQL server endpoint. Try a config like this:
engine.listen({
port: port,
expressApp: fidserver.app,
graphqlPaths: ['/client'] // removed "graphql"
});

Resources