#4386·graphiql

createGraphiQLFetcher: support subscriptions over HTTP multipart/mixed (Apollo subscriptionSpec=1.0), not just WebSockets

Author: ItaiYosephiCreated Jul 5, 2026Updated Jul 5, 2026

Is your feature request related to a problem? Please describe.

createGraphiQLFetcher hardwires every subscription operation to a WebSocket transport. In create-fetcher/createFetcher.ts, once an operation is detected as a subscription it goes straight to getWsFetcher:

typescript
if (isSubscription) {
  const wsFetcher = await getWsFetcher(options, fetcherOpts);
  if (!wsFetcher) {
    throw new Error(
      `Your GraphiQL createFetcher is not properly configured for websocket subscriptions yet. …`,
    );
  }
  return wsFetcher(graphQLParams);
}

and getWsFetcher only ever resolves from wsClient / subscriptionUrl / legacyClient — all WebSocket. There is no code path that lets a subscription be delivered over HTTP.

This blocks a mainstream setup: servers that deliver subscriptions over HTTP multipart/mixed using the Apollo multipart subscription protocol (subscriptionSpec=1.0), which is what Apollo Client + Apollo Router/GraphOS use by default. For these APIs there is no WebSocket endpoint at all — subscriptions ride the same HTTP endpoint as queries/mutations. Pointing GraphiQL at such an API makes queries/mutations work, but any subscription throws the "not properly configured for websocket subscriptions" error, even though the transport is plain HTTP that the fetcher is otherwise already talking to.

Note this is distinct from the existing multipart support: createMultipartFetcher handles @defer/@stream incremental delivery (deferSpec, { hasNext, incremental } frames) and is only wired to queries/mutations. Apollo multipart subscriptions are a different framing ({ payload } envelopes + heartbeats), so the existing multipart reader can't be reused as-is, and subscription ops never reach it anyway.

Describe the solution you'd like

Let createGraphiQLFetcher deliver subscriptions over HTTP multipart when configured/negotiated — e.g. an opt-in option such as subscriptionSpec: '1.0' (or auto-detection), routing subscription operations to a multipart reader instead of getWsFetcher when no WS client is configured. The reader would:

  • POST to options.url with Accept: multipart/mixed;subscriptionSpec="1.0", application/json (boundary graphql)
  • yield part.payload for each message part (containing data / errors / extensions)
  • silently skip heartbeat parts ({})
  • terminate on the fatal-error frame ({ "payload": null, "errors": [...] }) and on the closing boundary

meros (already a dependency) can parse the stream; only the per-part envelope handling differs from the @defer path.

Describe alternatives you've considered

  • Consumer-side custom fetcher — works, but every GraphiQL-based tool sitting in front of an Apollo Router/Client stack has to reimplement the same multipart subscription reader. First-class support in the toolkit is the natural home.
  • graphql-sse / SSE — a different protocol; GraphiQL's current EventSource handling isn't graphql-sse-compliant either (enisdenjo/graphql-sse#8), so it's not an out-of-the-box path.

Additional context