Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
benjie opened this issue Dec 17, 2019 · 7 comments

Comments

@benjie
Copy link
Member

benjie commented Dec 17, 2019

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?

@sungam3r
Copy link
Contributor

sometimes this feature can come in handy

@imolorhe
Copy link

imolorhe commented Dec 22, 2019

@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

@benjie
Copy link
Member Author

benjie commented Jan 7, 2020

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.

@sjparsons
Copy link
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?

@benjie
Copy link
Member Author

benjie commented Jul 4, 2020

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

@acao
Copy link
Member

acao commented Mar 4, 2024

@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!

@enisdenjo
Copy link
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
Projects
None yet
Development

No branches or pull requests

7 participants