Using the @defer
and @stream
directives#
GraphQL Helix supports @defer
and @stream
directives out-of-the-box, provided you use the appropriate version of graphql-js
. When either directive is used, processRequest
will return a MULTIPART_RESPONSE
result, which you can then use to return a multipart/mixed
response. You can use sendResult
or sendMultipartResponseResult
helpers to send a valid response strucut easily. Here's an example of how this is implemented behind the scenes:
// This is what sendResult / sendMultipartResponseResult is doing behind the scenes
if (result.type === "MULTIPART_RESPONSE") {
// Indicate that this is a multipart response and the connection should be kept open.
res.writeHead(200, {
Connection: "keep-alive",
"Content-Type": 'multipart/mixed; boundary="-"',
"Transfer-Encoding": "chunked",
});
// If the client closes the connection, we unsubscribe to prevent memory leaks.
req.on("close", () => {
result.unsubscribe();
});
res.write("---");
// Subscribe to new results. The callback will be called with the
// ExecutionResult object that should be sent back to the client for each chunk.
await result.subscribe((result) => {
const chunk = Buffer.from(JSON.stringify(formatResult(result)), "utf8");
const data = ["Content-Type: application/json; charset=utf-8", "Content-Length: " + String(chunk.length), "", chunk];
if (result.hasNext) {
data.push("---");
}
res.write(data.join("\r\n"));
});
// The Promise returned by `subscribe` will only resolve once all chunks have been emitted,
// at which point we can end the request.
res.write("\r\n-----\r\n");
res.end();
}
See the here for a complete example.
The examples used in this repo are compatible with client-side libraries like meros and fetch-multipart-graphql.