apollographql / apollo-link-persisted-queries

Persisted Query support with Apollo Link
MIT License
306 stars 33 forks source link

Question: Does apollo-link-persisted-queries support apollo-link-ws ? #18

Open 4F2E4A2E opened 6 years ago

4F2E4A2E commented 6 years ago

And if yes, can someone provide an example?

freshollie commented 4 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)),
});

image

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.

NateScarlet commented 4 years ago

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;
    }
  };
}