From 9cfb85e4dac9dd1d4d1a05dbb95a94deca014d27 Mon Sep 17 00:00:00 2001 From: Savas Vedova Date: Thu, 12 Oct 2023 14:38:52 +0200 Subject: [PATCH] chore: re-use invoke api logic --- src/middlewares/express.ts | 37 ++++++++++++------------------ src/utils/callbacks.ts | 47 ++++++++++++++++++++++++++------------ 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/middlewares/express.ts b/src/middlewares/express.ts index 171c713..600282a 100644 --- a/src/middlewares/express.ts +++ b/src/middlewares/express.ts @@ -1,6 +1,6 @@ -import type { Request, Response, Handler } from "express"; -import type { AlternativeSyntax } from "~/utils/callbacks"; +import type { Request, Response } from "express"; import path from "node:path"; +import { invokeApiHandler } from "~/utils/callbacks"; import { matchPath } from "~/router"; interface Options { @@ -34,29 +34,20 @@ export default (opts: Options) => async (req: Request, res: Response) => { `/${path.join(apiDir, route).replace(/^\/+/, "")}` ); - Promise.resolve(handler.default(req, res, () => {})).then( - (r: AlternativeSyntax | void) => { - if (typeof r !== "undefined" && typeof r === "object") { - const isBodyAnObject = typeof r.body === "object"; - - if (isBodyAnObject) { - res.setHeader("Content-Type", "application/json"); - } - - Object.keys(r.headers || {}).forEach((key) => { - res.setHeader(key, r.headers![key]); - }); + invokeApiHandler(handler, req, res).then((data) => { + if (!data) { + res.status(200); + res.end(); + return; + } - res.status(r.status || r.statusCode || 200); + Object.keys(data.headers || {}).forEach((key) => { + res.setHeader(key, data.headers![key]); + }); - if (isBodyAnObject) { - res.send(JSON.stringify(r.body)); - } else { - res.send(r.body); - } - } - } - ); + res.status(data.status || 200); + res.send(data.body); + }); return; } diff --git a/src/utils/callbacks.ts b/src/utils/callbacks.ts index c86b928..258fdbe 100644 --- a/src/utils/callbacks.ts +++ b/src/utils/callbacks.ts @@ -34,11 +34,37 @@ let cachedFiles: WalkFile[]; export interface AlternativeSyntax { body?: string; - headers?: Record; + headers?: Record; statusCode?: number; status?: number; // Alias for statusCode } +export const invokeApiHandler = ( + handler: any, + req: any, + res: any +): Promise => { + 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 = {}; + + 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 @@ -47,7 +73,7 @@ export const handleApi = ( cachedFiles = walkTree(apiDir); } - return new Promise((resolve) => { + return new Promise(async (resolve) => { const req = new Request(event); const res = new Response(req); @@ -61,18 +87,11 @@ export const handleApi = ( if (file) { try { const mod = require(path.join(file.path, file.name)); - const ret = mod.default ? mod.default(req, res) : mod(req, res); - - // Allow function to return a value instead of using `response.end` - Promise.resolve(ret).then((r: AlternativeSyntax) => { - if (typeof r !== "undefined" && typeof r === "object") { - resolve({ - body: r.body, - headers: r.headers, - status: r.statusCode || r.status, - }); - } - }); + const ret = await invokeApiHandler(mod, req, res); + + if (ret) { + resolve(ret); + } return; } catch (e) {