apollo-link-persisted-queries
apollo-link-persisted-queries copied to clipboard
Question: Does apollo-link-persisted-queries support apollo-link-ws ?
And if yes, can someone provide an example?
For those looking for the answer to this, my investigation suggests no at the moment. Or at least no if you use subscription-transport-ws and apollo-server
Firstly subscription-transport-ws doesn't support sending queries without a .query, attached (https://github.com/apollographql/subscriptions-transport-ws/blob/567fca89cb4578371877faee09e1630dcddff544/src/client.ts#L400)
if (!query) {
throw new Error('Must provide a query.');
}
So, even when you do add a persisted queries link in front of apollo-link-ws you will find the websocket link and subscription client do not strip the query from the payload, making it rather useless.
const client = new ApolloClient({
cache,
typeDefs,
resolvers,
link: createPersistedQueryLink().concat(new WebSocketLink(subscriptionClient)),
});

Secondly, if you write a middleware to strip the query field from the payload if the query has a persisted extension:
const subscriptionClient = new SubscriptionClient(`${BACKEND}/graphql`, {
reconnect: true,
}).use([
{
applyMiddleware: (operation, next) => {
if (operation.extensions?.persistedQuery) {
// as this middleware has to mutate the existing object
// this is the only option
// eslint-disable-next-line no-param-reassign
delete operation.query;
}
next();
},
},
]);
and you patch subscriptions-transport-ws to allow payloads without a query the server will not accept the transport over ws because "no document was provided".
This seems to be missing feature in apollo-server where it doesn't parse the incoming persistedQuery during the onOperation hook: https://github.com/apollographql/apollo-server/blob/4e5c0f692564781ff3f1fc6f722a87210f63dcf6/packages/apollo-server-core/src/ApolloServer.ts#L686
I am going to look into putting a PR in to make apollo-server-core correctly convert the persistedQuery hash to a document, as it does for http queries, and then look into a PR for making subscription-transport-ws allow payloads to go out without .query attribute.
There is my workaround to use persisted query with subscription:
/**
* workaround to use persisted query with subscription
* https://github.com/apollographql/apollo-link-persisted-queries/issues/18
*/
function patchSubscriptionClient(client: SubscriptionClient) {
// make client to respect
// `operation.getContext().http.includeQuery`
// so apq link can work
client.use([
{
applyMiddleware: (operation, next) => {
if (operation.query) {
operation.setContext({ query: operation.query });
}
const ctx = operation.getContext();
const includeQuery: boolean | undefined = ctx?.http?.includeQuery;
if (includeQuery) {
operation.query = ctx.query;
} else {
delete operation.query;
}
next();
},
},
]);
// allow empty query
const c = (client as unknown) as Record<string, unknown>;
const raw = c.checkOperationOptions as (...args: unknown[]) => unknown;
c.checkOperationOptions = (...args: unknown[]) => {
try {
return raw(...args);
} catch (err) {
if (err instanceof Error && err.message === 'Must provide a query.') {
return;
}
throw err;
}
};
}