impl basic server and route handling

This commit is contained in:
Lee 2023-11-20 10:59:32 +00:00
parent 2dd25e250c
commit 4afd3a2c84
7 changed files with 221 additions and 2 deletions

@ -5,7 +5,7 @@
"main": "dist/index.js", "main": "dist/index.js",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts", "build": "tsup src/index.ts --format cjs",
"start": "node dist/index.js", "start": "node dist/index.js",
"dev": "nodemon --exec ts-node src/index.ts" "dev": "nodemon --exec ts-node src/index.ts"
}, },
@ -16,6 +16,7 @@
"typescript": "^5.2.2" "typescript": "^5.2.2"
}, },
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.21",
"nodemon": "^3.0.1", "nodemon": "^3.0.1",
"ts-node": "^10.9.1" "ts-node": "^10.9.1"
} }

69
pnpm-lock.yaml generated

@ -19,6 +19,9 @@ dependencies:
version: 5.2.2 version: 5.2.2
devDependencies: devDependencies:
'@types/express':
specifier: ^4.17.21
version: 4.17.21
nodemon: nodemon:
specifier: ^3.0.1 specifier: ^3.0.1
version: 3.0.1 version: 3.0.1
@ -394,11 +397,77 @@ packages:
/@tsconfig/node16@1.0.4: /@tsconfig/node16@1.0.4:
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
/@types/body-parser@1.19.5:
resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
dependencies:
'@types/connect': 3.4.38
'@types/node': 20.9.2
dev: true
/@types/connect@3.4.38:
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
dependencies:
'@types/node': 20.9.2
dev: true
/@types/express-serve-static-core@4.17.41:
resolution: {integrity: sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==}
dependencies:
'@types/node': 20.9.2
'@types/qs': 6.9.10
'@types/range-parser': 1.2.7
'@types/send': 0.17.4
dev: true
/@types/express@4.17.21:
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
dependencies:
'@types/body-parser': 1.19.5
'@types/express-serve-static-core': 4.17.41
'@types/qs': 6.9.10
'@types/serve-static': 1.15.5
dev: true
/@types/http-errors@2.0.4:
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
dev: true
/@types/mime@1.3.5:
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
dev: true
/@types/mime@3.0.4:
resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==}
dev: true
/@types/node@20.9.2: /@types/node@20.9.2:
resolution: {integrity: sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg==} resolution: {integrity: sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg==}
dependencies: dependencies:
undici-types: 5.26.5 undici-types: 5.26.5
/@types/qs@6.9.10:
resolution: {integrity: sha512-3Gnx08Ns1sEoCrWssEgTSJs/rsT2vhGP+Ja9cnnk9k4ALxinORlQneLXFeFKOTJMOeZUFD1s7w+w2AphTpvzZw==}
dev: true
/@types/range-parser@1.2.7:
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
dev: true
/@types/send@0.17.4:
resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
dependencies:
'@types/mime': 1.3.5
'@types/node': 20.9.2
dev: true
/@types/serve-static@1.15.5:
resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==}
dependencies:
'@types/http-errors': 2.0.4
'@types/mime': 3.0.4
'@types/node': 20.9.2
dev: true
/@types/webidl-conversions@7.0.3: /@types/webidl-conversions@7.0.3:
resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==}
dev: false dev: false

@ -1 +1,4 @@
console.log("hi"); import { SsrServer } from "./server/impl/ssrServer";
// Init the SSR Server
const server = new SsrServer();

@ -0,0 +1,14 @@
import { Request, Response } from "express";
import { Route } from "../route";
export default class TestRoute extends Route {
constructor() {
super({
path: "/test",
});
}
async handle(req: Request, res: Response) {
res.send("Hello World!");
}
}

34
src/route/route.ts Normal file

@ -0,0 +1,34 @@
import { Request, Response } from "express";
type RouteType = {
/**
* The path to handle
*/
path: string;
};
export abstract class Route {
private path: string;
constructor({ path }: RouteType) {
this.path = path;
console.log(`Created route handler for ${path}`);
}
/**
* Handle the incoming request
*
* @param req the request
* @param res the response
*/
abstract handle(req: Request, res: Response): void;
/**
* Get the path of the route
*
* @returns the path
*/
getPath() {
return this.path;
}
}

@ -0,0 +1,19 @@
import TestRoute from "../../route/impl/testRoute";
import Server from "../server";
export class SsrServer extends Server {
constructor() {
super({
port: 3000,
routes: [new TestRoute()],
});
}
public preInit(): void {
console.log("preInit");
}
public postInit(): void {
console.log("postInit");
}
}

79
src/server/server.ts Normal file

@ -0,0 +1,79 @@
import express, { Express } from "express";
import { Route } from "../route/route";
type ServerConfig = {
port: number;
routes?: Route[];
};
export default class Server {
/**
* The port that this server is listening on.
*/
private port: number;
/**
* The express server.
*/
private server: Express;
/**
* The routes that this server is serving.
*/
private routes: Route[] = [];
constructor({ port, routes }: ServerConfig) {
this.port = port;
if (routes) {
this.routes.push(...routes);
}
// Create the express server
this.server = express();
this.preInit();
// Handle the routes
for (const route of this.routes) {
this.server.all(route.getPath(), (req, res) => route.handle(req, res));
}
console.log(`Registered ${this.routes.length} routes`);
// Start listening on the specified port
this.server.listen(this.port, () => {
console.log(`Server listening on port ${this.port}`);
this.postInit();
});
}
/**
* Returns the port that this server is listening on.
*
* @returns {number} the port
*/
public getPort() {
return this.port;
}
/**
* Registers a list of routes.
*
* @param route the routes to register
*/
public registerRoute(...routes: Route[]) {
this.routes.push(...routes);
}
public getRoute(path: string): Route | undefined {
return this.routes.find((route) => route.getPath() === path);
}
/**
* Gets called before the server starts listening.
*/
public preInit(): void {}
/**
* Gets called after the server starts listening.
*/
public postInit(): void {}
}