Add HTTP routing and server management classes
- Introduced UserApiRoute for managing user-related API routes - Implemented HttpRouteManager for registering and retrieving HTTP routes - Created HttpServer class to initialize and start an Express server with route management - Added middleware and static route handling in HttpServer
This commit is contained in:
25
src/api/UserApiRoute.ts
Normal file
25
src/api/UserApiRoute.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import type { RouteHandler } from "../net/http/HttpRouteManger";
|
||||||
|
|
||||||
|
|
||||||
|
export class UserApiRoute {
|
||||||
|
private readonly _getRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _postRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _putRoutes: Record<string, RouteHandler> = {};
|
||||||
|
private readonly _deleteRoutes: Record<string, RouteHandler> = {};
|
||||||
|
|
||||||
|
public getGETRoutes(): Record<string, RouteHandler> {
|
||||||
|
return this._getRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPOSTRoutes(): Record<string, RouteHandler> {
|
||||||
|
return this._postRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPUTRoutes(): Record<string, RouteHandler> {
|
||||||
|
return this._putRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDELETERoutes(): Record<string, RouteHandler> {
|
||||||
|
return this._deleteRoutes;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
src/net/http/HttpRouteManger.ts
Normal file
95
src/net/http/HttpRouteManger.ts
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
import assertUnreachable from '../../lang/assertUnreachable';
|
||||||
|
import type express from 'express';
|
||||||
|
|
||||||
|
export type HttpRoute = string;
|
||||||
|
export type RoutePath = string;
|
||||||
|
export type RouteHandler = (request: express.Request, response: express.Response) => void | Promise<void>;
|
||||||
|
|
||||||
|
export class HttpRouteManager {
|
||||||
|
private readonly _staticGETRoutes: Record<HttpRoute, RoutePath>;
|
||||||
|
private readonly _getRoutes: Record<HttpRoute, RouteHandler>;
|
||||||
|
private readonly _postRoutes: Record<HttpRoute, RouteHandler>;
|
||||||
|
private readonly _putRoutes: Record<HttpRoute, RouteHandler>;
|
||||||
|
private readonly _deleteRoutes: Record<HttpRoute, RouteHandler>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._staticGETRoutes = {};
|
||||||
|
this._getRoutes = {};
|
||||||
|
this._postRoutes = {};
|
||||||
|
this._putRoutes = {};
|
||||||
|
this._deleteRoutes = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerStaticRoute(routePath: RoutePath, destination: string) {
|
||||||
|
if (this._staticGETRoutes[routePath]) {
|
||||||
|
throw new Error(`Error: Static route [${routePath}] is already defined`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._staticGETRoutes[routePath] = destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public register(verb: 'GET' | 'POST' | 'PUT' | 'DELETE', route: string, handler: RouteHandler) {
|
||||||
|
const isRouteDefined = (routes: Record<HttpRoute, RouteHandler>, routePath: string) => !!routes[routePath];
|
||||||
|
|
||||||
|
switch (verb) {
|
||||||
|
case 'GET':
|
||||||
|
if (isRouteDefined(this._getRoutes, route)) {
|
||||||
|
throw new Error(`Error: Route [${route}] is already defined`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._getRoutes[route] = handler;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'POST':
|
||||||
|
if (isRouteDefined(this._postRoutes, route)) {
|
||||||
|
throw new Error(`Error: Route [${route}] is already defined`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._postRoutes[route] = handler;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'PUT':
|
||||||
|
if (isRouteDefined(this._putRoutes, route)) {
|
||||||
|
throw new Error(`Error: Route [${route}] is already defined`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._putRoutes[route] = handler;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'DELETE':
|
||||||
|
if (isRouteDefined(this._deleteRoutes, route)) {
|
||||||
|
throw new Error(`Error: Route [${route}] is already defined`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._deleteRoutes[route] = handler;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assertUnreachable(verb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getStaticGETRoutes(): Record<HttpRoute, RoutePath> {
|
||||||
|
return this._staticGETRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getGETRoutes(): Record<HttpRoute, RouteHandler> {
|
||||||
|
return this._getRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPOSTRoutes(): Record<HttpRoute, RouteHandler> {
|
||||||
|
return this._postRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPUTRoutes(): Record<HttpRoute, RouteHandler> {
|
||||||
|
return this._putRoutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDELETERoutes(): Record<HttpRoute, RouteHandler> {
|
||||||
|
return this._deleteRoutes;
|
||||||
|
}
|
||||||
|
}
|
||||||
56
src/net/http/HttpServer.ts
Normal file
56
src/net/http/HttpServer.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import express, {type Express} from 'express';
|
||||||
|
import type {HttpRouteManager} from './HttpRouteManger';
|
||||||
|
import path from 'path';
|
||||||
|
import morgan from 'morgan';
|
||||||
|
|
||||||
|
type Routes = Record<string, RouteHandler>;
|
||||||
|
type RouteHandler = (req: express.Request, res: express.Response) => void | Promise<void>;
|
||||||
|
|
||||||
|
export class HttpServer {
|
||||||
|
private _app: Express;
|
||||||
|
|
||||||
|
constructor(private readonly routeManager: HttpRouteManager) {
|
||||||
|
this._app = express();
|
||||||
|
this._app.use(morgan('dev'));
|
||||||
|
|
||||||
|
this.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public start(port: number) {
|
||||||
|
this._app.listen(port, () => console.log('Server listening on [%o]', port));
|
||||||
|
}
|
||||||
|
|
||||||
|
private initialize() {
|
||||||
|
this.applyMiddleware();
|
||||||
|
this.applyStaticRoutes();
|
||||||
|
this.applyRoutes('get', this.routeManager.getGETRoutes());
|
||||||
|
this.applyRoutes('post', this.routeManager.getPOSTRoutes());
|
||||||
|
this.applyRoutes('put', this.routeManager.getPUTRoutes());
|
||||||
|
this.applyRoutes('delete', this.routeManager.getDELETERoutes());
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyRoutes(httpVerb: 'get' | 'post' | 'put' | 'delete', routes: Routes) {
|
||||||
|
Object.entries(routes).forEach(([route, handler]) => this._app[httpVerb as keyof typeof this._app](route, handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyStaticRoutes() {
|
||||||
|
Object.entries(this.routeManager.getStaticGETRoutes()).forEach(([route, destination]) => {
|
||||||
|
this._app.use(
|
||||||
|
route,
|
||||||
|
express.static(path.resolve(destination), {
|
||||||
|
setHeaders: (res, filePath) => {
|
||||||
|
console.log(filePath);
|
||||||
|
if (filePath.endsWith('.js')) {
|
||||||
|
res.setHeader('Content-Type', 'application/javascript');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyMiddleware() {
|
||||||
|
this._app.use(express.json());
|
||||||
|
this._app.use(express.urlencoded({extended: true}));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user