Clean up how route handlers are called

This commit is contained in:
Michael Wolf
2025-03-07 21:22:31 -06:00
parent 6ed81e871f
commit ecdbedc135
4 changed files with 64 additions and 27 deletions

View File

@@ -1,39 +1,75 @@
import { services } from "./services.ts"; import { services } from "./services.ts";
import { import {
DenoRequest, DenoRequest,
massageMethod,DenoResponse, DenoResponse,
InternalHandler,
massageMethod,
Method, Method,
ProcessedRoute, ProcessedRoute,
Request, Request as Request,
Route, Route,
} from "./types.ts"; } from "./types.ts";
import { routes } from "./routes.ts"; import { routes } from "./routes.ts";
services.logging.log({ source: "logging", text: ["1"] }); services.logging.log({ source: "logging", text: ["1"] });
const processedRoutes: ProcessedRoute[] = routes.map( const processedRoutes: { [K in Method]: ProcessedRoute[] } = {
"GET": [],
"POST": [],
"PUT": [],
"PATCH": [],
"DELETE": [],
};
function isPromise<T>(value: T | Promise<T>): value is Promise<T> {
return typeof (value as any)?.then === "function";
}
routes.forEach(
(route: Route, _idx: number, _allRoutes: Route[]) => { (route: Route, _idx: number, _allRoutes: Route[]) => {
const pattern: URLPattern = new URLPattern({ pathname: route.path }); const pattern: URLPattern = new URLPattern({ pathname: route.path });
const method: Method = route.method; const methodList = route.methods;
const handler = async (denoRequest: DenoRequest) => {
const handler: InternalHandler = async (denoRequest: DenoRequest) => {
const method = massageMethod(denoRequest.method);
if (!methodList.includes(method)) {
// XXX: Worth asserting this?
}
const p = new URL(denoRequest.url);
const path = p.pathname;
const req: Request = { const req: Request = {
pattern: route.pattern, pattern: route.path,
path: denoRequest.path, path,
method: massageMethod(denoRequest.method), method,
parameters: { one: 1, two: 2 }, parameters: { one: 1, two: 2 },
denoRequest, denoRequest,
}; };
return route.handler(req);
const retval = route.handler(req);
if (isPromise(retval)) {
return await retval;
} else {
return retval;
}
}; };
const retval: ProcessedRoute = { pattern, method, handler }; for (const [_idx, method] of methodList.entries()) {
const pr: ProcessedRoute = { pattern, method, handler };
return retval; processedRoutes[method].push(pr);
}
}, },
); );
async function handler(req: DenoRequest): Promise<DenoResponse> { async function handler(req: DenoRequest): Promise<DenoResponse> {
for (const [idx, pr] of processedRoutes.entries()) { const m = req.method;
const m1 = massageMethod(m);
const byMethod = processedRoutes[m1];
for (const [_idx, pr] of byMethod.entries()) {
const match = pr.pattern.exec(req.url); const match = pr.pattern.exec(req.url);
if (match) { if (match) {
const resp = await pr.handler(req); const resp = await pr.handler(req);

View File

@@ -30,18 +30,18 @@ const okText = (out: string) => {
const routes: Route[] = [ const routes: Route[] = [
{ {
path: "/slow", path: "/slow",
methods: ["get"], methods: ["GET"],
handler: async (_req) => { handler: async (_req: Request) => {
console.log("starting slow request"); console.log("starting slow request");
await sleep(10); await sleep(2);
console.log("finishing slow request"); console.log("finishing slow request");
return okText("that was slow"); return okText("that was slow");
}, },
}, },
{ {
path: "/list", path: "/list",
methods: ["get"], methods: ["GET"],
handler: async (_req) => { handler: (_req: Request) => {
const code = httpCodes.success.OK; const code = httpCodes.success.OK;
const lr = (rr: Route[]) => { const lr = (rr: Route[]) => {
const ret = rr.map((r: Route) => { const ret = rr.map((r: Route) => {
@@ -61,8 +61,8 @@ const routes: Route[] = [
}, },
{ {
path: "/ok", path: "/ok",
methods: ["get"], methods: ["GET"],
handler: async (_req) => { handler: (_req: Request) => {
const code = httpCodes.success.OK; const code = httpCodes.success.OK;
const rn = services.random.randomNumber(); const rn = services.random.randomNumber();
@@ -75,8 +75,8 @@ const routes: Route[] = [
}, },
{ {
path: "/alsook", path: "/alsook",
methods: ["get"], methods: ["GET"],
handler: async (_req) => { handler: (_req) => {
const code = httpCodes.success.OK; const code = httpCodes.success.OK;
return { return {
code, code,

View File

@@ -4,7 +4,6 @@ import { randomNumber } from "https://deno.land/x/random_number/mod.ts";
import { config } from "./config.ts"; import { config } from "./config.ts";
import { getLogs, log } from "./logging.ts"; import { getLogs, log } from "./logging.ts";
//const database = Client({ //const database = Client({
//}) //})

View File

@@ -18,13 +18,13 @@ const methodParser = z.union([
export type Method = z.infer<typeof methodParser>; export type Method = z.infer<typeof methodParser>;
const massageMethod = (input: string): Method => { const massageMethod = (input: string): Method => {
const r = methodParser.parse(input.toUpperCase()) const r = methodParser.parse(input.toUpperCase());
return r; return r;
}; };
export type DenoRequest = globalThis.Request; export type DenoRequest = globalThis.Request;
export type DenoResponse=globalThis.Response; export type DenoResponse = globalThis.Response;
export type UserRequest = {}; export type UserRequest = {};
export type Request = { export type Request = {
pattern: string; pattern: string;
@@ -33,10 +33,14 @@ export type Request = {
parameters: object; parameters: object;
denoRequest: globalThis.Request; denoRequest: globalThis.Request;
}; };
export type InternalHandler = (req: DenoRequest) => Promise<Response>;
export type Handler = (req: Request) => Promise<Response> | Response;
export type ProcessedRoute = { export type ProcessedRoute = {
pattern: URLPattern; pattern: URLPattern;
method: Method; method: Method;
handler: Handler; handler: InternalHandler;
}; };
export type Response = { export type Response = {
@@ -45,8 +49,6 @@ export type Response = {
result: string; result: string;
}; };
export type Handler = (req: Request) => Promise<Response>;
export type Route = { export type Route = {
path: string; path: string;
methods: Method[]; methods: Method[];