Files
diachron/backend/diachron/routing.ts

94 lines
3.3 KiB
TypeScript

import { contentTypes } from "./content-types";
import { httpCodes } from "./http-codes";
import express, {
type NextFunction,
type Request as ExpressRequest,
type Response as ExpressResponse,
} from "express";
import {isRedirect, InternalHandler, AuthenticationRequired,
AuthorizationDenied, Call,type Method, type ProcessedRoute,methodParser, type Result, type Route,massageMethod } from "./types";
import { runWithContext } from "./context";
import { Session } from "./auth";import { request } from "./request";
import { match } from "path-to-regexp";
type ProcessedRoutes= {[K in Method]: ProcessedRoute[] }
const processRoutes=(routes:Route[]) :ProcessedRoutes => {
const retval:ProcessedRoutes= {
GET: [],
POST: [],
PUT: [],
PATCH: [],
DELETE: [],
};
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 (
expressRequest: ExpressRequest,
): Promise<Result> => {
const method = massageMethod(expressRequest.method);
console.log("method", method);
if (!methodList.includes(method)) {
// XXX: Worth asserting this?
}
console.log("request.originalUrl", expressRequest.originalUrl);
// Authenticate the request
const auth = await request.auth.validateRequest(expressRequest);
const req: Call = {
pattern: route.path,
path: expressRequest.originalUrl,
method,
parameters: { one: 1, two: 2 },
request: expressRequest,
user: auth.user,
session: new Session(auth.session, auth.user),
};
try {
const retval = await runWithContext({ user: auth.user }, () =>
route.handler(req),
);
return retval;
} catch (error) {
// Handle authentication errors
if (error instanceof AuthenticationRequired) {
return {
code: httpCodes.clientErrors.Unauthorized,
contentType: contentTypes.application.json,
result: JSON.stringify({
error: "Authentication required",
}),
};
}
if (error instanceof AuthorizationDenied) {
return {
code: httpCodes.clientErrors.Forbidden,
contentType: contentTypes.application.json,
result: JSON.stringify({ error: "Access denied" }),
};
}
throw error;
}
};
for (const [_idx, method] of methodList.entries()) {
const pr: ProcessedRoute = { matcher, method, handler };
retval[method].push(pr);
}
});
return retval;
}
export{processRoutes}