UNPKG

graphql-yoga

Version:
66 lines (65 loc) • 3.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.defaultRequestIdHeader = exports.defaultGenerateRequestId = void 0; exports.getRequestIdHeaderName = getRequestIdHeaderName; exports.useRequestId = useRequestId; const request_id_js_1 = require("../utils/request-id.js"); const defaultGenerateRequestId = () => globalThis.crypto.randomUUID(); exports.defaultGenerateRequestId = defaultGenerateRequestId; exports.defaultRequestIdHeader = 'x-request-id'; function getRequestIdHeaderName(opts) { return opts?.headerName || exports.defaultRequestIdHeader; } /** * Reads a request id the host integration already assigned to the native request object it * passes through the server context (e.g. Fastify's `request.id`, or an Express/Koa * request-id middleware that sets `req.id`), before Yoga ever saw the request. * * This lets Yoga's own id generation defer to a host's existing correlation id instead of * minting an unrelated one of its own, without the host needing to disable `useRequestId` and * reimplement the logger scoping it provides. */ function getHostRequestId(serverContext) { const req = serverContext?.req; return typeof req?.id === 'string' && req.id.length > 0 ? req.id : undefined; } /** * Correlates everything happening while handling a request under a single request id. * * A request id the host integration already set on the native request object (see * {@link getHostRequestId}) is preferred first, so Yoga's logs always agree with the host's own; * otherwise, if `trustHeader` is enabled (the default), the `x-request-id` header of the * incoming request is used if present and usable (see {@link getRequestId}); otherwise, one is * generated. It is then added to the server context's `log`ger as the `requestId` attribute, and * set on the outgoing response's headers. */ function useRequestId(opts) { const requestIdByRequest = new WeakMap(); const headerName = getRequestIdHeaderName(opts); const trustHeader = opts?.trustHeader ?? true; const generateRequestId = opts?.generateRequestId || exports.defaultGenerateRequestId; return { onRequest({ request, fetchAPI, serverContext }) { const generate = () => generateRequestId({ request, fetchAPI, context: serverContext, }); let requestId = getHostRequestId(serverContext); requestId ??= trustHeader ? (0, request_id_js_1.getRequestId)(request.headers.get(headerName), generate) : generate(); requestIdByRequest.set(request, requestId); // `useConfigInServerContext` runs before this plugin and puts the logger in the server // context. It can still be missing when this plugin is used on its own, in which case the // request id is only propagated through the headers. serverContext.log &&= serverContext.log.child({ requestId }); }, onResponse({ request, response }) { const requestId = requestIdByRequest.get(request); if (requestId) { response.headers.set(headerName, requestId); } }, }; }