upload current sources
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* RFC 9457 Problem Details for HTTP APIs — the governed contract
|
||||
* (docs/api/worker.openapi.json) specifies `application/problem+json` for all
|
||||
* error responses (400/401/404/502/503).
|
||||
*
|
||||
* We omit the `type` member: per RFC 9457 §3.1.1 an absent `type` is
|
||||
* equivalent to "about:blank", in which case `title` mirrors the HTTP status
|
||||
* phrase — which is exactly what we send.
|
||||
*/
|
||||
|
||||
import type { FastifyReply } from 'fastify';
|
||||
|
||||
export const PROBLEM_CONTENT_TYPE = 'application/problem+json';
|
||||
|
||||
export interface ProblemDetails {
|
||||
title: string;
|
||||
status: number;
|
||||
detail?: string;
|
||||
}
|
||||
|
||||
export function sendProblem(
|
||||
reply: FastifyReply,
|
||||
status: number,
|
||||
title: string,
|
||||
detail?: string,
|
||||
/** Extra response headers (e.g. `Retry-After` on 503). */
|
||||
headers: Record<string, string> = {},
|
||||
): FastifyReply {
|
||||
const body: ProblemDetails = detail === undefined ? { title, status } : { title, status, detail };
|
||||
// Serialize explicitly: Fastify's default JSON serializer targets
|
||||
// application/json, so send a pre-serialized string under the problem type.
|
||||
reply.code(status).header('content-type', `${PROBLEM_CONTENT_TYPE}; charset=utf-8`);
|
||||
for (const [name, value] of Object.entries(headers)) {
|
||||
reply.header(name, value);
|
||||
}
|
||||
return reply.send(JSON.stringify(body));
|
||||
}
|
||||
Reference in New Issue
Block a user