-
Notifications
You must be signed in to change notification settings - Fork 2
/
api.ts
94 lines (79 loc) · 2.57 KB
/
api.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
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
94
import type { RequestEvent } from "~/request";
import type { ServerlessResponse } from "~/response";
import type { WalkFile } from "~/utils/filesys";
import path from "node:path";
import Request from "~/request";
import Response from "~/response";
import { matchPath, walkTree } from "~/utils/filesys";
let cachedFiles: WalkFile[];
export interface AlternativeSyntax {
body?: string;
headers?: Record<string, string | string[]>;
statusCode?: number;
status?: number; // Alias for statusCode
}
export const invokeApiHandler = (
handler: any,
req: any,
res: any
): Promise<ServerlessResponse | void> => {
const ret = handler?.default ? handler.default(req, res) : handler(req, res);
// Allow function to return a value instead of using `response.end`
return Promise.resolve(ret).then((r: AlternativeSyntax) => {
if (typeof r !== "undefined" && typeof r === "object") {
const isBodyAnObject = typeof r.body === "object";
const headers: Record<string, string | string[]> = {};
if (isBodyAnObject) {
headers["Content-Type"] = "application/json";
}
return {
body: typeof r.body === "string" ? r.body : JSON.stringify(r.body),
headers: { ...headers, ...r.headers },
status: r.statusCode || r.status,
};
}
});
};
export const handleApi = (
event: RequestEvent,
apiDir: string
): Promise<ServerlessResponse> => {
if (typeof cachedFiles === "undefined") {
cachedFiles = walkTree(apiDir);
}
return new Promise(async (resolve) => {
const req = new Request(event);
const res = new Response(req);
res.on("sk-end", (data: ServerlessResponse) => {
resolve(data);
});
// This is what we do here:
// /api/my-path?query-param => /my-path
const requestPath =
"/" + (req.url?.split(/[\?#]/)[0].split("/").slice(2).join("/") || "");
const file = matchPath(cachedFiles, requestPath, req.method);
if (file) {
try {
const mod = require(path.join(file.path, file.name));
const ret = await invokeApiHandler(mod, req, res);
if (ret) {
resolve({ ...ret, logs: req.logger?.logs() });
}
return;
} catch (e) {
if (
e instanceof Error &&
e.message?.includes("handler is not a function")
) {
console.error(
"API Function does not export a default method. See https://www.stormkit.io/docs/features/writing-api for more information."
);
} else {
console.error(e);
}
}
}
res.writeHead(404, "Not found");
res.end();
});
};