GithubHelp home page GithubHelp logo

Comments (9)

jbaxleyiii avatar jbaxleyiii commented on May 19, 2024

@mxstbr I think the issue here is with the attempts function. When persisted query link fails, it doesn't strip the extensions field, but rather adds the query field and tells http to send both. So this bit:

const isPersistedQuery =
        operation.extensions &&
        operation.extensions.persistedQuery &&
        operation.extensions.persistedQuery.sha256Hash;
      // Don't retry persisted query tries since the persisted query link will
      // retry those will the full query text
      if (isPersistedQuery) return false;

will always return false even after failure since the persisted query link is before it. If you remove that, it should work! Here is a first run test to see if I understood what is happening! https://github.com/apollographql/apollo-link-persisted-queries/pull/13/files#diff-a15885c1b39ba5a6c3bfc050319fdaf3R56

from apollo-link-persisted-queries.

mxstbr avatar mxstbr commented on May 19, 2024

The problem is, if I remove that bit the RetryLink will keep retrying the persisted query call with the hash, rather than letting the PersistedQueryLink retry will the full query text.

from apollo-link-persisted-queries.

mxstbr avatar mxstbr commented on May 19, 2024

This is what happens with that bit of code removed:

persisted-queries

Note how all the network requests only send the hash, they never send the full query text. That's what I'm trying to fix here.

Some notes:

  • I'm using v7.1.0-alpha.1 of the apollo-upload-client link by @jaydenseric, which added support for persisted queries. (ref: jaydenseric/apollo-upload-client#61)
  • I observe the same behavior when I replace the createUploadLink call with createHttpLink, so that's not the culprit here.
  • I observe the same behavior when I remove all the custom options from RetryLink

Here is my entire Apollo Client code, maybe that helps:

Click to reveal client.js
export const createClient = (options) => {
  const cache = new InMemoryCache({
    fragmentMatcher: new IntrospectionFragmentMatcher({
      introspectionQueryResultData,
    }),
    cacheResolvers,
    dataIdFromObject,
  });

  const headers = options.token
    ? {
        authorization: `Bearer ${options.token}`,
      }
    : undefined;

  const retryLink = new RetryLink({
    attempts: (count, operation, error) => {
      const isMutation =
        operation &&
        operation.query &&
        operation.query.definitions &&
        Array.isArray(operation.query.definitions) &&
        operation.query.definitions.some(
          def =>
            def.kind === 'OperationDefinition' && def.operation === 'mutation'
        );

      // Retry mutations for a looong time, those are very important to us so we want them to go through eventually
      if (isMutation) {
        return !!error && count < 25;
      }

      // Retry queries for way less long as this just ends up showing
      // loading indicators for that whole time which is v annoying
      return !!error && count < 6;
    },
  });

  const persistedQueryLink = createPersistedQueryLink();

  const uploadLink = createUploadLink({
    uri: API_URI,
    credentials: 'include',
    headers,
  });

  const httpLink = ApolloLink.from([persistedQueryLink, retryLink, uploadLink])

  // Websocket link for subscriptions
  const wsLink = new WebSocketLink({
    uri: `${IS_PROD ? `wss://${window.location.host}` : 'ws://localhost:3001'}/websocket`,
    options: {
      reconnect: true,
    },
  });

  // Switch between the two links based on operation
  const link = split(
    ({ query }) => {
      const { kind, operation } = getMainDefinition(query);
      return kind === 'OperationDefinition' && operation === 'subscription';
    },
    wsLink,
    httpLink
  );

  return new ApolloClient({
    link,
    cache: window.__DATA__ ? cache.restore(window.__DATA__) : cache,
    ssrForceFetchDelay: 100,
    queryDeduplication: true,
  });
};

from apollo-link-persisted-queries.

mxstbr avatar mxstbr commented on May 19, 2024

Hmm, maybe this actually isn't related to the RetryLink at all. Even without the RetryLink the PersistedQueryLink never sends the full query text. Digging in.

from apollo-link-persisted-queries.

mxstbr avatar mxstbr commented on May 19, 2024

Okay so this might not be related to the RetryLink after all, sorry for the confusion.

Looking at the verbose logs in the browser console I see "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3001/api. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)." (our client runs at localhost:3000, API at localhost:3001)

This doesn't happen before the persisted query link PR. The only changes I've made are:

  1. Run Apollo Engine in development (otherwise persisted queries don't work)
  2. Add the persisted query link
Click for the full diff

engine.js:

 // @flow
 import { Engine } from 'apollo-engine';
 
+// In development don't send any performance data to Engine, we only start it
+// for the persisted queries
+const origins =
+  process.env.NODE_ENV === 'development'
+    ? {
+        maxConcurrentRequests: 0,
+      }
+    : undefined;
+
 export default new Engine({
   graphqlPort: 3001,
   endpoint: '/api',
   engineConfig: {
+    stores: [
+      {
+        name: 'pq',
+        inMemory: {
+          cacheSize: '5000000',
+        },
+      },
+    ],
+    persistedQueries: {
+      store: 'pq',
+    },
     logging: {
       level: 'WARN',
     },
     apiKey: process.env.APOLLO_ENGINE_API_KEY,
   },
+  origins,
 });

api/middlewares.js:

 // Start apollo engine
-if (process.env.NODE_ENV === 'production' && !process.env.FORCE_DEV) {
-  const engine = require('./engine').default;
-  middlewares.use(engine.expressMiddleware());
-}
+const engine = require('./engine').default;
+middlewares.use(engine.expressMiddleware());

client.js:

-  // HTTP Link for queries and mutations including file uploads
-  const httpLink = retryLink.concat(
-    createUploadLink({
-      uri: API_URI,
-      credentials: 'include',
-      headers,
-    })
-  );
+  const persistedQueryLink = createPersistedQueryLink();
+
+  const uploadLink = createUploadLink({
+    uri: API_URI,
+    credentials: 'include',
+    headers,
+  });
+
+  const httpLink = ApolloLink.from([persistedQueryLink, retryLink, uploadLink]);

Maybe the problem is that the proxy blocks cross-origin requests for some reason? I couldn't find anything in the documentation on how to add support for that, but our API server does use the cors middleware.

from apollo-link-persisted-queries.

wireforce avatar wireforce commented on May 19, 2024

@mxstbr Did you ever find a solution for this? I suspect that there is something fishy going on with this library and CORS. I cant get it to accept cross origin requests...

from apollo-link-persisted-queries.

declanelcocks avatar declanelcocks commented on May 19, 2024

@jbaxleyiii Going to drop my experience here too as it seems closely related to @mxstbr (came here via his post on apollo-upload-client). The problem for me is that my second query does not pass the correct payload to the API.

First query:

------WebKitFormBoundaryvNYFgEzAXZqcZmYL
Content-Disposition: form-data; name="operations"

{"operationName":"UploadFile","variables":{"file":null},"extensions":{"persistedQuery":{"version":1,"sha256Hash":"c08bdd3daf357d9b08033d4f338f09d6cd88dee402772683d51dcaa0eea7d88c"}}}
------WebKitFormBoundaryvNYFgEzAXZqcZmYL
Content-Disposition: form-data; name="map"

{"0":["variables.file"]}
------WebKitFormBoundaryvNYFgEzAXZqcZmYL
Content-Disposition: form-data; name="0"; filename="blob"
Content-Type: image/png

This one will respond as expected with PersistedQueryNotFound, but here's the payload of the client's response to that:

{"operationName":"UploadFile","variables":{"file":null},"extensions":{"persistedQuery":{"version":1,"sha256Hash":"c08bdd3daf357d9b08033d4f338f09d6cd88dee402772683d51dcaa0eea7d88c"}},"query":"mutation UploadFile($file: Upload!) {\n  uploadFile(file: $file) {\n    success\n    __typename\n  }\n}\n"}

The file itself is not actually passed during the retry, which will result in the retry throwing an error that $file is null. I can also confirm that after removing createPersistedQueryLink, the mutation works fine in every situation.

from apollo-link-persisted-queries.

jaydenseric avatar jaydenseric commented on May 19, 2024

@declanelcocks Keep in mind that the HTTP link from apollo-upload-client modifies the operation for the request, see jaydenseric/apollo-upload-client#81. I don't know if this is what is happening in your situation, but if the operation gets used again after that link all the files will have been replaced with null.

from apollo-link-persisted-queries.

declanelcocks avatar declanelcocks commented on May 19, 2024

@jaydenseric from what you wrote, I assume that using files specifically would not work at all with persisted queries, since the multipart form data will not be persisted across to the retry query? I think my only option at the moment would be to disable persisted queries for that session if the operation is UploadFile as the retry will always fail.

from apollo-link-persisted-queries.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.