Open 4F2E4A2E opened 6 years ago
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;
}
};
}
And if yes, can someone provide an example?