feat: add simple router

This commit is contained in:
2024-11-16 23:10:54 +08:00
parent 926c0a09cd
commit 5e38740c7b
5 changed files with 118 additions and 752 deletions

62
src/router-simple.ts Normal file
View File

@@ -0,0 +1,62 @@
import { pathToRegexp, match, Key } from 'path-to-regexp';
import type { IncomingMessage, ServerResponse } from 'http';
type Req = IncomingMessage & { params?: Record<string, string> };
interface Route {
method: string;
regexp: RegExp;
keys: Key[];
handlers: Array<(req: Req, res: ServerResponse) => Promise<void> | void>;
}
/**
* SimpleRouter
*/
export class SimpleRouter {
routes: Route[] = [];
constructor() {
// console.log('AppSimple initialized');
}
use(method: string, route: string, ...fns: Array<(req: Req, res: ServerResponse) => Promise<void> | void>) {
const handlers = Array.isArray(fns) ? fns.flat() : [];
const pattern = pathToRegexp(route);
this.routes.push({ method: method.toLowerCase(), regexp: pattern.regexp, keys: pattern.keys, handlers });
return this;
}
get(route: string, ...fns: Array<(req: Req, res: ServerResponse) => Promise<void> | void>) {
return this.use('get', route, ...fns);
}
post(route: string, ...fns: Array<(req: Req, res: ServerResponse) => Promise<void> | void>) {
return this.use('post', route, ...fns);
}
parse(req: Req, res: ServerResponse) {
const { pathname } = new URL(req.url, 'http://localhost');
const method = req.method.toLowerCase();
const route = this.routes.find((route) => {
const matchResult = route.regexp.exec(pathname);
if (matchResult && route.method === method) {
const params: Record<string, string> = {};
route.keys.forEach((key, i) => {
params[key.name] = matchResult[i + 1];
});
req.params = params;
return true;
}
});
if (route) {
const { handlers } = route;
return handlers.reduce((promiseChain, handler) => promiseChain.then(() => Promise.resolve(handler(req, res))), Promise.resolve());
}
if (!res?.headersSent && res && res?.end) {
res.statusCode = 404;
res.end('Not Found');
} else {
console.error('Not Found');
}
}
}