Comments (9)
@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.
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.
This is what happens with that bit of code removed:
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 theapollo-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 withcreateHttpLink
, 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.
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.
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:
- Run Apollo Engine in development (otherwise persisted queries don't work)
- 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.
@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.
@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.
@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.
@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)
- Option to only send APQ on queries not mutations HOT 4
- Struggling to configure the client HOT 1
- CORS GETs issue a PREFLIGHT OPTIONS call. Can we swtich the content-type or not? HOT 3
- Questions about hashing cost client side.
- Possible memory leak in query cache
- Question: use only GET but avoid send full query and combine GET and POST HOT 1
- How to precompute query hashes, store it, and use it to whitelist persisted queries. HOT 17
- Version 0.2.2 has not been published to npm yet
- PersistedQueryNotSupported errors will stop all other extensions
- This package breaks refetchQueries in Mutations
- The query hash that is generated by apollo-android does not match the query hash that is generated by apollo-link-persisted-queries
- Status code for PersistedQueryNotFound HOT 1
- Elaboration on usage of useGETForHashedQueries with apollo-link-batch-http
- Don't mix require with import statements, it breaks rollup bundling HOT 4
- ApolloLink is missing onError and setOnError properties HOT 4
- Symbol.for() usage breaks in IE11
- Help with Sample Apollo Client code to test APQ (Automated Persistent Queries)
- Support for [email protected]. HOT 1
- Need help with persisted queries, is anyone available for hire?
- No guidance for how to use APQ to do query whitelisting
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from apollo-link-persisted-queries.