graphql-sse
Version:
Zero-dependency, HTTP/1 safe, simple, GraphQL over Server-Sent Events Protocol server and client
93 lines (92 loc) • 3.11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createHandler = void 0;
const handler_1 = require("../handler");
/**
* The ready-to-use handler for [express](https://expressjs.com).
*
* Errors thrown from the provided options or callbacks (or even due to
* library misuse or potential bugs) will reject the handler or bubble to the
* returned iterator. They are considered internal errors and you should take care
* of them accordingly.
*
* For production environments, its recommended not to transmit the exact internal
* error details to the client, but instead report to an error logging tool or simply
* the console.
*
* ```ts
* import express from 'express'; // yarn add express
* import { createHandler } from 'graphql-sse/lib/use/express';
* import { schema } from './my-graphql';
*
* const handler = createHandler({ schema });
*
* const app = express();
*
* app.use('/graphql/stream', async (req, res) => {
* try {
* await handler(req, res);
* } catch (err) {
* console.error(err);
* res.writeHead(500).end();
* }
* });
*
* server.listen(4000);
* console.log('Listening to port 4000');
* ```
*
* @category Server/express
*/
function createHandler(options) {
const handler = (0, handler_1.createHandler)(options);
return async function handleRequest(req, res) {
const [body, init] = await handler({
method: req.method,
url: req.url,
headers: {
get(key) {
const header = req.headers[key];
return Array.isArray(header) ? header.join('\n') : header;
},
},
body: () => new Promise((resolve, reject) => {
if (req.body) {
// body was parsed by middleware
return resolve(req.body);
}
let body = '';
req.on('data', (chunk) => (body += chunk));
req.once('error', reject);
req.once('end', () => {
req.off('error', reject);
resolve(body);
});
}),
raw: req,
context: { res },
});
res.writeHead(init.status, init.statusText, init.headers);
if (!body || typeof body === 'string') {
return new Promise((resolve) => res.end(body, () => resolve()));
}
res.once('close', body.return);
for await (const value of body) {
const closed = await new Promise((resolve, reject) => {
if (!res.writable) {
// response's close event might be late
resolve(true);
}
else {
res.write(value, (err) => (err ? reject(err) : resolve(false)));
}
});
if (closed) {
break;
}
}
res.off('close', body.return);
return new Promise((resolve) => res.end(resolve));
};
}
exports.createHandler = createHandler;