Request IDs
The correlation problem
Your API logs show three errors at 14:32. Which one caused the user’s failed order? The errors have timestamps, levels, and messages — but no way to tell which log entries belong to the same request.
A request ID is a unique identifier assigned to every incoming request. Every log entry produced during that request includes the same ID. To trace the user’s failed order, search for their request ID — all related logs appear together.
Generating request IDs
function generateRequestId(): string {
return `req_${crypto.randomUUID().replace(/-/g, "").slice(0, 12)}`;
}
// "req_a1b2c3d4e5f6" Short, unique, prefixed with req_ so it is recognizable in logs. Generated once per request, included in every log entry and the response.
Assigning in onRequest
export const app = setup({
onRequest: ({ request }) => {
const requestId = generateRequestId();
const url = new URL(request.url);
logger.info("request started", {
requestId,
method: request.method,
path: url.pathname,
});
return { requestId, startTime: Date.now() };
},
// ...
}); The onRequest callback generates the ID and returns it in locals. Every route handler and the onResponse callback can access it via c.locals.requestId.
[!NOTE] Hectoday HTTP’s
onRequestreturns locals that are available in route handlers viac.locals. The Error Handling course used this for error context. The API Versioning course used it for version tracking. Now we use it for request IDs.
Including in responses
Clients should know their request ID — for bug reports, support tickets, and debugging:
onResponse: ({ response, locals }) => {
if (locals.requestId) {
response.headers.set("X-Request-Id", locals.requestId);
}
}, The client receives X-Request-Id: req_a1b2c3d4e5f6 in the response headers. If they report a problem, they include the request ID. You search the logs for that ID and see everything that happened.
[!NOTE] The HTTP from Scratch course’s Custom Headers lesson introduced
X-Request-Id. Now you know where it comes from — the logging system generates it and attaches it to every response.
Accepting client-provided request IDs
Some clients (especially internal services) want to provide their own request ID for end-to-end tracing:
onRequest: ({ request }) => {
const requestId = request.headers.get("x-request-id") ?? generateRequestId();
// ...
return { requestId, startTime: Date.now() };
}, If the client sends X-Request-Id, use it. Otherwise, generate one. This enables tracing across services: service A generates a request ID, passes it to service B, which passes it to service C. All logs across all services share the same ID.
Exercises
Exercise 1: Generate a request ID in onRequest. Include it in a log entry. Return it in the response via X-Request-Id.
Exercise 2: Make 3 requests. Search the logs for one specific request ID. Verify all entries for that request appear.
Exercise 3: Send a request with a custom X-Request-Id header. Verify the server uses it instead of generating a new one.
Why include the request ID in the response headers?