UNPKG

@httpc/kit

Version:

httpc toolbox for building function-based API with minimal code and end-to-end type safety

46 lines (45 loc) 2.04 kB
import { HttpCServerError, httpCall, Metadata } from "@httpc/server"; import { useInjected } from "../di"; export function httpController(constructor) { function createMethodCall(methodName) { return (...args) => { const instance = useInjected(constructor); const method = instance[methodName]; if (!method) { throw new HttpCServerError("callNotFound"); } return method.apply(instance, args); }; } const { CALL_MIDDLEWARE: CLASS_MIDDLEWARE = [], ...controllerMetadata } = getAllMetadata(constructor); const calls = new Map(); for (const methodName of getMethods(constructor)) { const { CALL_ACCESS = "write", CALL_MIDDLEWARE = [], ...callMetadata } = getAllMetadata(constructor, methodName); if (!CALL_ACCESS) continue; calls.set(methodName, httpCall(CALL_ACCESS, Metadata({ ...controllerMetadata, ...callMetadata }), ...CLASS_MIDDLEWARE, ...CALL_MIDDLEWARE, createMethodCall(methodName))); } return Object.fromEntries(calls); } function getMethods(constructor) { const methods = Object.entries(Object.getOwnPropertyDescriptors(constructor.prototype)) .filter(([key, descriptor]) => { if (key === "constructor") return false; if (typeof descriptor.value !== "function") return false; const access = Reflect.getMetadata("CALL_ACCESS", constructor.prototype, key) || "write"; if (!access) return false; return true; }); return methods.map(([key]) => key); } function getAllMetadata(target, property) { const metadata = property ? Reflect.getMetadataKeys(target.prototype, property) .map(key => [key, Reflect.getMetadata(key, target.prototype, property)]) : Reflect.getMetadataKeys(target.prototype) .map(key => [key, Reflect.getMetadata(key, target.prototype)]); return Object.fromEntries(metadata); }