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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
"use client";
import { ZodTypeAny, z } from "zod";
import {
ZNewBookmarkedLinkRequest,
zGetLinksResponseSchema,
} from "./types/api/links";
import serverConfig from "./config";
const BASE_URL = `${serverConfig.api_url}/api/v1`;
export type FetchError = {
status?: number;
message?: string;
};
async function doRequest<Schema extends ZodTypeAny>(
_path: string,
respSchema: Schema,
_opts: RequestInit | undefined,
): Promise<[z.infer<typeof respSchema>, undefined] | [undefined, FetchError]>;
async function doRequest<_Schema>(
_path: string,
_respSchema: undefined,
_opts: RequestInit | undefined,
): Promise<[undefined, undefined] | [undefined, FetchError]>;
type InputSchema<T> = T extends ZodTypeAny ? T : undefined;
async function doRequest<T>(
path: string,
respSchema?: InputSchema<T>,
opts?: RequestInit,
): Promise<
| (InputSchema<T> extends ZodTypeAny
? [z.infer<InputSchema<T>>, undefined]
: [undefined, undefined])
| [undefined, FetchError]
> {
try {
const res = await fetch(`${BASE_URL}${path}`, opts);
if (!res.ok) {
return [
undefined,
{ status: res.status, message: await res.text() },
] as const;
}
if (!respSchema) {
return [undefined, undefined] as const;
}
let parsed = respSchema.safeParse(await res.json());
if (!parsed.success) {
return [
undefined,
{ message: `Failed to parse response: ${parsed.error.toString()}` },
] as const;
}
return [parsed.data, undefined] as const;
} catch (error: any) {
return [
undefined,
{ message: `Failed to execute fetch request: ${error}` },
] as const;
}
}
export default class APIClient {
static async getLinks() {
return await doRequest(`/links`, zGetLinksResponseSchema, {
next: { tags: ["links"] },
});
}
static async bookmarkLink(url: string) {
const body: ZNewBookmarkedLinkRequest = {
url,
};
return await doRequest(`/links`, undefined, {
method: "POST",
body: JSON.stringify(body),
});
}
static async unbookmarkLink(linkId: string) {
return await doRequest(`/links/${linkId}`, undefined, {
method: "DELETE",
});
}
}
|