Skip to content

X-GraphQL-Event-Stream for being notified that the GraphQL schema has updated #48

Open

Description

@benjie

Server-sent events are a perfect mechanism for informing a GraphQL client that the schema has been updated. They don't require the complexity of websockets, and they are uni-directional.

I'm proposing that when introspecting a GraphQL API, if the header X-GraphQL-Event-Stream is detected then interested clients should subscribe to the text/event-stream at that (relative or absolute) URL and when it receives the change event it should automatically re-introspect the GraphQL schema.

Not much code should be required to implement this, just something like:

// refreshSchema is a function you provide which triggers re-introspection

const streamUrl = response.headers["x-graphql-event-stream"];
if (streamUrl) {
  const endpointUrl = new URL(endpoint);
  const streamUrl = new URL(streamUrl, endpointUrl);
  if (endpointUrl.host !== streamUrl.host) {
    throw new Error(
      `Stream and endpoint hosts don't match - '${streamUrl.host}' !== '${endpointUrl.host}'`
    );
  }
  const eventSource = new EventSource(streamUrl);

  eventSource.addEventListener("change", refreshSchema, false);
  eventSource.addEventListener("open", () => { /* ... */ }, false);
  eventSource.addEventListener("error", () => { /* ... */ }, false);
}

(You may want to throttle the refreshSchema method.)

This has been baked into PostGraphile for a while; I opened an implementation PR to @skevy's GraphiQL.app a good while ago; and @imolorhe has implemented it independently in Altair. Samuel wrote more about it here: https://sirmuel.design/a-better-graphql-developer-experience-with-x-graphql-event-stream-1256aef96f24. We'll probably be implementing it in the new version of GraphiQL too, once we have the plugin system in place.

What are your thoughts?

Activity

  1. sungam3r commented on Dec 17, 2019

    @sungam3r
    Contributor

    sometimes this feature can come in handy

  2. imolorhe commented on Dec 22, 2019

    @imolorhe

    @benjie do you have a simple GraphQL server repo that has this implemented for demo purposes? I've been finding it hard to see this implementation actually working

  3. benjie commented on Jan 7, 2020

    @benjie
    MemberAuthor

    No; but it is implemented in a separate small file:

    https://github.com/graphile/postgraphile/blob/0ad482d5f9c4e8314d86f0ffc9f12d9e320578b1/src/postgraphile/http/setupServerSentEvents.ts

    (Some of this file handles the differences between Koa and Express/Connect, so you may be able to trim a fair bit of it.)

    That file is called from a middleware with this code:

          // Setup an event stream so we can broadcast events to graphiql, etc.
          if (pathname === '/graphql/stream') {
            if (req.headers.accept !== 'text/event-stream') {
              res.statusCode = 405;
              res.end();
              return;
            }
            setupServerSentEvents(req, res, options);
            return;
          }

    The other thing is we have an EventEmitter and when the GraphQL schema has changed we publish the schemas:changed event to it; but your implementation may do something different.

  4. sjparsons commented on Jul 1, 2020

    @sjparsons
    Contributor

    This is a fascinating idea. I really like it. I can also see that it'd be nice to see a standard around this mechanism. I'm thinking it'd be best for this to be post-1.0 release. What do you think?

  5. benjie commented on Jul 4, 2020

    @benjie
    MemberAuthor

    Definitely post 1.0 is fine. It’d be optional anyhow.

  6. added this to the Post 1.0 release milestone on Jul 6, 2020
  7. acao commented on Mar 4, 2024

    @acao

    @enisdenjo what do you think of adopting this for graphql-http? would you be open to a PR that allows the user to opt into this for NODE_ENV=development or whatever they configure? or should it come as a separate middleware?

    I would like to implement this for the editor tooling (LSP server and GraphiQL), finally!

  8. enisdenjo commented on Mar 4, 2024

    @enisdenjo
    Member

    What exactly? Add the header? I don't think it's necessary to integrate this into the library as it can simply be added by the user itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions