This multipart protocol is built on the Incremental Delivery over HTTP spec. The protocol delivers continuous updates in the format:

--graphql
Content-Type: application/json

{"payload": {"data": { "message": "Hello World!"}}}}
--graphql
Content-Type: application/json

{"payload": {"data": { "message": "How are you?"}}}}
--graphql
Content-Type: application/json

{}
--graphql
Content-Type: application/json

{"payload": {"data": { "message": "Mic Drop"}}}}
--graphql--

You can use multipart messages by setting Accept: multipart/mixed on a GraphQL subscription POST request. Try out the following example:

Example

curl --location 'https://demo-router.fly.dev/graphql' \
--header 'Accept: multipart/mixed' \
--data '{"query":"subscription test {\n currentTime {unixTime}\n}","operationName":"test"}'

Client Integration

To implement Server-Sent Events (SSE) with a GraphQL POST request, you’ll typically need to use a more custom approach than the standard EventSource. Here’s a full example using JavaScript’s fetch API with the ReadableStream interface. You can also copy paste this example in the Developer Console to test it.

var myHeaders = new Headers();
myHeaders.append("Accept", "multipart/mixed");

var raw = JSON.stringify({
  "query": "subscription test {\n currentTime {unixTime}\n}",
  "operationName": "test"
});

var requestOptions = {
  method: 'POST',
  headers: myHeaders,
  body: raw,
  redirect: 'follow'
};

const response = await fetch("https://demo-router.fly.dev/graphql", requestOptions)

// To recieve data as a string we use TextDecoderStream class in pipethrough
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader()

// Consume unless you reload the page. You can also use the AbortController API to close the connection.
while (true) {
  const {value, done} = await reader.read();
  if (done) break;
  // Remove the data: prefix and parse the message
  console.log('Received', JSON.parse(value.replace("data: ", "")));
}

This code doesn’t handle connection issues and retries.