Search code examples
graphqlserver-sent-eventseventsource

GraphQL subscription using server-sent events & EventSource


I'm looking into implementing a "subscription" type using server-sent events as the backing api.

What I'm struggling with is the interface, to be more precise, the http layer of such operation.

The problem:

Using the native EventSource does not support:

  1. Specifying an HTTP method, "GET" is used by default.
  2. Including a payload (The GraphQL query)

While #1 is irrefutable, #2 can be circumvented using query parameters.

Query parameters have a limit of ~2000 chars (can be debated) which makes relying solely on them feels too fragile.

The solution I'm thinking of is to create a dedicated end-point for each possible event.

For example: A URI for an event representing a completed transaction between parties:

/graphql/transaction-status/$ID

Will translate to this query in the server:

subscription TransactionStatusSubscription {
    status(id: $ID) {
        ready
    }
}

The issues with this approach is:

  1. Creating a handler for each URI-to-GraphQL translation is to be added.
  2. Deploy a new version of the server
  3. Loss of the flexibility offered by GraphQL -> The client should control the query
  4. Keep track of all the end-points in the code base (back-end, front-end, mobile)

There are probably more issues I'm missing.

Is there perhaps a better approach that you can think of? One the would allow a better approach at providing the request payload using EventSource?


Solution

  • Subscriptions in GraphQL are normally implemented using WebSockets, not SSE. Both Apollo and Relay support using subscriptions-transport-ws client-side to listen for events. Apollo Server includes built-in support for subscriptions using WebSockets. If you're just trying to implement subscriptions, it would be better to utilize one of these existing solutions.

    That said, there's a library for utilizing SSE for subscriptions here. It doesn't look like it's maintained anymore, but you can poke around the source code to get some ideas if you're bent on trying to get SSE to work. Looking at the source, it looks like the author got around the limitations you mention above by initializing each subscription with a POST request that returns a subscription id.