apollographql / apollo-server

🌍  Spec-compliant and production ready JavaScript GraphQL server that lets you develop in a schema-first way. Built for Express, Connect, Hapi, Koa, and more.
https://www.apollographql.com/docs/apollo-server/
MIT License
13.79k stars 2.03k forks source link

Automatic persisted query in Apollo Client and Server is not working getting PERSISTED_QUERY_NOT_FOUND error #2429

Closed techyrajeev closed 5 years ago

techyrajeev commented 5 years ago

I tried to use highly advertised Automatic persisted query for performance benefits in Graphql based system but after spending three days I couldn't fix below problem. Apollo documents has lots of 404 pages for this topic if you try to look up -

On Client:

I used

import { createPersistedQueryLink } from "apollo-link-persisted-queries";

const httpLink = createHttpLink({uri: API_URL })

const apqSwitch = createPersistedQueryLink({useGETForHashedQueries: true}).concat(httpLink);

  let links = [errorlink, stateLink, setSiteIdHeaderLink, apqLinkSwitch]

  const link = ApolloLink.from(links)

  const client = new ApolloClient({
    defaultOptions: {
      watchQuery: {
        errorPolicy: 'all'
      },
      query: {
        errorPolicy: 'all'
      },
      mutate: {
        errorPolicy: 'all'
      }
    },
    link,
    cache,
    connectToDevTools: true,
    credentials: 'include',
  })

  return { client, persistor }
}

client dependencies:

"apollo-boost": "^0.1.22",
"apollo-cache-inmemory": "^1.3.11",
"apollo-cache-persist": "^0.1.1",
"apollo-client": "^2.4.7",
"apollo-link": "^1.2.3",
"apollo-link-batch-http": "^1.2.8",
"apollo-link-http": "^1.5.9",
"apollo-link-persisted-queries": "^0.2.2",
"apollo-link-retry": "^2.2.5",
"apollo-link-schema": "^1.1.1",

On Server:

import { InMemoryLRUCache } from 'apollo-server-caching';
const { RedisCache } = require('apollo-server-cache-redis');

const server = new ApolloServer({
  ...root,
  resolverValidationOptions: {
    requireResolversForResolveType: false,
  },
  persistedQueries: {
    /*
    cache: new CustomRedis(),
    */
    cache: new RedisCache({
      host: 'localhost',
      port: xxxx,
    }),
  },
  formatError,
  formatResponse: (response, query) => formatResponse({ response, query }),
  dataSources
});

Server dependencies:

"apollo-datasource-rest": "^0.3.2",
"apollo-errors": "^1.9.0",
"apollo-server-cache-redis": "^0.3.1",
"apollo-server-caching": "^0.3.1",
"apollo-server-express": "^2.4.8",
"cors": "^2.8.5",
"dataloader": "^1.4.0",
"express": "^4.16.3",
"glob": "^7.1.3",
"graphql": "^14.0.2",
"graphql-import": "^0.7.1",
"graphql-resolvers": "^0.2.2",

Observations:

  1. From client side I see sha1 has is being send to server.

variables=%7B%7D&extensions=%7B%22persistedQuery%22%3A%7B%22version%22%3A1%2C%22sha256Hash%22%3A%22fd4c5f1ae3sfsf6ee0f0710b8d303a9703db7a6708b401278e2fd664f56f4e91762f%22%7D%7D

  1. Server is looking for sha1 in the redis cache but it couldn't find
  2. Server returns PersistedQueryNotFound","MsgCode":"PERSISTED_QUERY_NOT_FOUND error to client

After that nothing happens there is no set operation is performed in redis cache and continuously getting PERSISTED_QUERY_NOT_FOUND error

Issue: APQ is not working

cnoter commented 5 years ago

Hi, as https://github.com/apollographql/apollo-link-persisted-queries this github readme says,

useGETForHashedQueries: set to true to use the HTTP GET method when sending the hashed version of queries (but not for mutations). GET requests require apollo-link-http 1.4.0 or newer, and are not compatible with apollo-link-batch-http.

I think your apollo-link-batch-http package and useGETForHashedQueries setting might have a compatibility problem.

ftatzky commented 5 years ago
const apqSwitch = createPersistedQueryLink({useGETForHashedQueries: true}).concat(httpLink);
let links = [errorlink, stateLink, setSiteIdHeaderLink, apqLinkSwitch]

You defined apqSwitch but in your array you use apqLinkSwitch which is undefined.

abernix commented 5 years ago

I realize it's been quite some time since you opened this, but if you haven't already figured this out (the suggestion from @ftatzky seems reasonable to me), I'd recommend taking this question to the Apollo community on Spectrum.chat to discuss it further. Thanks!

vNNi commented 3 years ago

Any updates? @techyrajeev i'm facing the same issue

glasser commented 3 years ago

@vNNi Can you share a reproduction (ie, a full sequence of instructions perhaps including a git clone or a codesandbox.io link that I can use to see your issue on my computer)?

Note that in Apollo Client 3, the persisted queries link is part of the main @apollo/client package; see https://www.apollographql.com/docs/react/api/link/persisted-queries/

vNNi commented 3 years ago

@glasser Hello! My issue (maybe) are related with timeout by the backend from client call and the persisted link return as PERSISTED_QUERY_NOT_FOUND.. I add more seconds and the times i receive not found was close to none. Obs: I'm using Apollo timeout link and persisted link together.

glasser commented 3 years ago

OK, that's not a reproduction so it won't help me help you.

kimutaiRop commented 3 years ago

I had the problem and it was because I had handled errors manually in my gateway (just to remove some exposing my server), if someone is doing that then know that the frontend client expect the all error as produced by the server, in my case I was only sending the message, you can check that error is for now query found then just permit the all thing

electerious commented 2 years ago

The problem is the formatError function. @apollo/client needs to know when it has to resend the query and it uses the GraphQL error message to detect the error. This doesn't work when returning a custom error via formatError.

The error message must be PersistedQueryNotFound. For some reason it uses the message instead of the unique PERSISTED_QUERY_NOT_FOUND error code to detect the error.

trevorr commented 2 years ago

The problem is the formatError function.

Great catch @electerious! You saved me a lot of time debugging why code that worked in test didn't work in production (where we scrub error messages).

glasser commented 2 years ago

@trevorr really good point — I've filed an issue in Apollo Client about this. Would probably make a pretty easy PR over there! https://github.com/apollographql/apollo-client/issues/10253