Barazo AppView backend barazo.forum
at main 119 lines 3.7 kB view raw
1// --------------------------------------------------------------------------- 2// Standard API error helpers 3// --------------------------------------------------------------------------- 4// Fastify's error handler checks `error.statusCode` to determine the HTTP 5// response code. These helpers create Error objects with the correct status 6// code and a structured message for consistent API responses. 7// --------------------------------------------------------------------------- 8 9import type { FastifyReply } from 'fastify' 10 11// --------------------------------------------------------------------------- 12// Shared OpenAPI error response schema 13// --------------------------------------------------------------------------- 14// All route files should import this instead of defining their own. 15// Matches the shape sent by the global error handler in app.ts and the 16// sendError helper below: { error, message, statusCode }. 17// --------------------------------------------------------------------------- 18 19export const errorResponseSchema = { 20 type: 'object' as const, 21 properties: { 22 error: { type: 'string' as const }, 23 message: { type: 'string' as const }, 24 statusCode: { type: 'integer' as const }, 25 }, 26} 27 28// --------------------------------------------------------------------------- 29// HTTP status text lookup 30// --------------------------------------------------------------------------- 31 32const HTTP_STATUS_TEXTS: Record<number, string> = { 33 400: 'Bad Request', 34 401: 'Unauthorized', 35 403: 'Forbidden', 36 404: 'Not Found', 37 409: 'Conflict', 38 429: 'Too Many Requests', 39 500: 'Internal Server Error', 40 502: 'Bad Gateway', 41} 42 43// --------------------------------------------------------------------------- 44// Structured error response helper 45// --------------------------------------------------------------------------- 46 47/** 48 * Send a structured error response with consistent shape: { error, message, statusCode }. 49 * 50 * - `error` – HTTP status text (e.g. "Bad Gateway") 51 * - `message` – human-readable description of the failure 52 * - `statusCode` – numeric HTTP status code 53 */ 54export function sendError(reply: FastifyReply, statusCode: number, message: string) { 55 return reply.status(statusCode).send({ 56 error: HTTP_STATUS_TEXTS[statusCode] ?? 'Error', 57 message, 58 statusCode, 59 }) 60} 61 62/** 63 * Base API error with an HTTP status code. 64 * Fastify uses `statusCode` on thrown errors to set the response status. 65 */ 66export class ApiError extends Error { 67 readonly statusCode: number 68 69 constructor(statusCode: number, message: string) { 70 super(message) 71 this.statusCode = statusCode 72 this.name = 'ApiError' 73 } 74} 75 76/** 77 * Create a 404 Not Found error. 78 * 79 * @param message - Human-readable description of what was not found. 80 */ 81export function notFound(message: string): ApiError { 82 return new ApiError(404, message) 83} 84 85/** 86 * Create a 403 Forbidden error. 87 * 88 * @param message - Human-readable reason for the denial. 89 */ 90export function forbidden(message: string): ApiError { 91 return new ApiError(403, message) 92} 93 94/** 95 * Create a 400 Bad Request error. 96 * 97 * @param message - Human-readable description of the validation failure. 98 */ 99export function badRequest(message: string): ApiError { 100 return new ApiError(400, message) 101} 102 103/** 104 * Create a 409 Conflict error. 105 * 106 * @param message - Human-readable description of the conflict. 107 */ 108export function conflict(message: string): ApiError { 109 return new ApiError(409, message) 110} 111 112/** 113 * Create a 429 Too Many Requests error. 114 * 115 * @param message - Human-readable description of the rate limit violation. 116 */ 117export function tooManyRequests(message: string): ApiError { 118 return new ApiError(429, message) 119}