-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttp.ts
51 lines (42 loc) · 1.62 KB
/
http.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import { z } from "./deps.ts";
import type { ZodType } from "./deps.ts";
export async function fetchJSONOnlyOk<T = unknown>(response: Response): Promise<T> {
if (!response.ok) {
throw await HTTPError.fromResponse(response);
}
return response.json() as Promise<T>;
}
export async function fetchNoBody<T extends undefined>(response: Response): Promise<T> {
if (response.status !== 204) {
throw await HTTPError.fromResponse(response);
}
return undefined as T;
}
export function fetchJSONZod<T extends ZodType, R extends z.output<T>>(validator: T): (response: Response) => Promise<R> {
return (response) =>
fetchJSONOnlyOk<unknown>(response)
.then((body) => validator.parseAsync(body));
}
export class HTTPError extends Error {
override readonly name = "HTTPError";
readonly status: number;
readonly path: string;
readonly body: unknown | undefined;
// deno-lint-ignore no-explicit-any
constructor(status: number, path: string, body: unknown | undefined, ...params: any[]) {
super(...params);
this.status = status;
this.path = path;
this.body = body;
}
override get message(): string {
const body = JSON.stringify(this.body);
return `Server responded with code ${this.status}${body ? `: ${body}` : ""}`;
}
static async fromResponse(response: Response): Promise<HTTPError> {
const url = new URL(response.url);
const body = response.body !== null ? await response.json() : undefined;
const { status } = response;
return new HTTPError(status, url.pathname, body);
}
}