Skip to content
File

Blob: src/worker/http.ts

typescript59 lines
1import type { Context } from "hono";
2import type { ContentfulStatusCode } from "hono/utils/http-status";
3 
4import { toCodecIssueDetails } from "@/lib/codec-errors";
5 
6export class HttpError extends Error {
7 public readonly status: ContentfulStatusCode;
8 public readonly code: string;
9 public readonly details: unknown;
10 
11 public constructor(status: ContentfulStatusCode, code: string, message: string, details?: unknown) {
12 super(message);
13 this.status = status;
14 this.code = code;
15 this.details = details;
16 }
17}
18 
19export const parseJson = async <T>(request: Request, codec: { assertDecode: (value: unknown) => T }): Promise<T> => {
20 let payload: unknown;
21 
22 try {
23 payload = (await request.json()) as unknown;
24 } catch (error) {
25 throw new HttpError(400, "invalid_json", "Request body must be valid JSON.", error);
26 }
27 
28 try {
29 return codec.assertDecode(payload);
30 } catch (error) {
31 throw new HttpError(400, "invalid_request", "Request body failed validation.", toCodecIssueDetails(error));
32 }
33};
34 
35export const toErrorResponse = (c: Context, error: unknown): Response => {
36 if (error instanceof HttpError) {
37 return c.json(
38 {
39 error: {
40 code: error.code,
41 message: error.message,
42 details: error.details ?? null,
43 },
44 },
45 error.status,
46 );
47 }
48 
49 return c.json(
50 {
51 error: {
52 code: "internal_error",
53 message: "An unexpected error occurred.",
54 },
55 },
56 500,
57 );
58};