UNPKG

graphql-yoga

Version:
60 lines (59 loc) • 2.91 kB
import { getRequestId } from '../utils/request-id.js'; export const defaultGenerateRequestId = () => globalThis.crypto.randomUUID(); export const defaultRequestIdHeader = 'x-request-id'; export function getRequestIdHeaderName(opts) { return opts?.headerName || 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. */ export function useRequestId(opts) { const requestIdByRequest = new WeakMap(); const headerName = getRequestIdHeaderName(opts); const trustHeader = opts?.trustHeader ?? true; const generateRequestId = opts?.generateRequestId || defaultGenerateRequestId; return { onRequest({ request, fetchAPI, serverContext }) { const generate = () => generateRequestId({ request, fetchAPI, context: serverContext, }); let requestId = getHostRequestId(serverContext); requestId ??= trustHeader ? 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); } }, }; }