Add a first cut at an express-based backend
This commit is contained in:
120
express/app.ts
Normal file
120
express/app.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import express, {
|
||||
Request as ExpressRequest,
|
||||
Response as ExpressResponse,
|
||||
} from "express";
|
||||
import { match } from "path-to-regexp";
|
||||
import { contentTypes } from "./content-types";
|
||||
import { httpCodes } from "./http-codes";
|
||||
import { routes } from "./routes";
|
||||
import { services } from "./services";
|
||||
// import { URLPattern } from 'node:url';
|
||||
import {
|
||||
Call,
|
||||
InternalHandler,
|
||||
Method,
|
||||
ProcessedRoute,
|
||||
Result,
|
||||
Route,
|
||||
massageMethod,
|
||||
methodParser,
|
||||
} from "./types";
|
||||
|
||||
const app = express();
|
||||
|
||||
services.logging.log({ source: "logging", text: ["1"] });
|
||||
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[]) => {
|
||||
// const pattern /*: URLPattern */ = new URLPattern({ pathname: route.path });
|
||||
const matcher = match<Record<string, string>>(route.path);
|
||||
const methodList = route.methods;
|
||||
|
||||
const handler: InternalHandler = async (
|
||||
request: ExpressRequest,
|
||||
): Promise<Result> => {
|
||||
const method = massageMethod(request.method);
|
||||
|
||||
console.log("method", method);
|
||||
|
||||
if (!methodList.includes(method)) {
|
||||
// XXX: Worth asserting this?
|
||||
}
|
||||
|
||||
console.log("request.originalUrl", request.originalUrl);
|
||||
console.log("beavis");
|
||||
|
||||
// const p = new URL(request.originalUrl);
|
||||
// const path = p.pathname;
|
||||
|
||||
// console.log("p, path", p, path)
|
||||
|
||||
console.log("ok");
|
||||
|
||||
const req: Call = {
|
||||
pattern: route.path,
|
||||
// path,
|
||||
path: request.originalUrl,
|
||||
method,
|
||||
parameters: { one: 1, two: 2 },
|
||||
request,
|
||||
};
|
||||
|
||||
const retval = await route.handler(req);
|
||||
return retval;
|
||||
};
|
||||
|
||||
for (const [_idx, method] of methodList.entries()) {
|
||||
const pr: ProcessedRoute = { matcher, method, handler };
|
||||
|
||||
processedRoutes[method].push(pr);
|
||||
}
|
||||
});
|
||||
|
||||
async function handler(
|
||||
req: ExpressRequest,
|
||||
_res: ExpressResponse,
|
||||
): Promise<Result> {
|
||||
const method = await methodParser.parseAsync(req.method);
|
||||
|
||||
const byMethod = processedRoutes[method];
|
||||
for (const [_idx, pr] of byMethod.entries()) {
|
||||
const match = pr.matcher(req.url);
|
||||
if (match) {
|
||||
console.log("match", match);
|
||||
const resp = await pr.handler(req);
|
||||
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
|
||||
const retval: Result = {
|
||||
code: httpCodes.clientErrors.NotFound,
|
||||
contentType: contentTypes.text.plain,
|
||||
result: "not found",
|
||||
};
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
app.use(async (req: ExpressRequest, res: ExpressResponse) => {
|
||||
const result0 = await handler(req, res);
|
||||
|
||||
const code = result0.code.code;
|
||||
const result = result0.result;
|
||||
|
||||
console.log(result);
|
||||
|
||||
res.status(code).send(result);
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
Reference in New Issue
Block a user