Skip to content

Commit

Permalink
Merge pull request #27 from zgid123/express-runner-feat/apply-excepti…
Browse files Browse the repository at this point in the history
…on-handler

[express-runner]: apply exception handler
  • Loading branch information
zgid123 authored Jul 20, 2024
2 parents d2961ab + 579d151 commit 7c4e9df
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 36 deletions.
2 changes: 1 addition & 1 deletion packages/@runners/express/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@abyss.ts/express-runner",
"version": "0.0.3",
"version": "0.0.4",
"author": "Alpha",
"repository": {
"type": "git",
Expand Down
53 changes: 46 additions & 7 deletions packages/@runners/express/src/Application.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
import { nanoid } from 'nanoid';
import bodyParser from 'body-parser';
import detectPort from 'detect-port';
import express, { type Express } from 'express';
import { createServer as createHttpServer } from 'http';
import { AbyssalContext, AbyssalApplication } from '@abyss.ts/core';
import express, { type Express, type Request, type Response } from 'express';
import {
AbyssalContext,
AbyssalApplication,
getExceptionCatchClassMetadata,
} from '@abyss.ts/core';

import { asyncStorage } from './asyncStorage';
import { mapRoutes } from './utils/routeUtils';
import { BaseExceptionHandler } from './BaseExceptionHandler';

import type { IRequest } from './interface';
import type { INext, IRequest, IResponse } from './interface';

export class ExpressApplication extends AbyssalApplication<ExpressApplication> {
#express: Express;
#baseExceptionHandler: BaseExceptionHandler;

static #app: ExpressApplication;

Expand All @@ -20,6 +26,7 @@ export class ExpressApplication extends AbyssalApplication<ExpressApplication> {

this.#express = express();
this._instance = this;
this.#baseExceptionHandler = new BaseExceptionHandler();
}

public static create(): ExpressApplication {
Expand All @@ -45,12 +52,14 @@ export class ExpressApplication extends AbyssalApplication<ExpressApplication> {
await this._mapMiddlewares();
const controllers = await this._mapControllers();

this._mapExceptionHandlers();
this.#applyMiddlewares();
this._mapInjections();

const [routes, router] = mapRoutes(controllers);

this.#express.use(router);
this.#applyExceptionHandlers();

const { port, isStrict } = this._port;
let runningPort = port;
Expand All @@ -71,13 +80,14 @@ export class ExpressApplication extends AbyssalApplication<ExpressApplication> {
}

#createContext(): void {
this.#express.use((req, _res, next) => {
this.#express.use((req, res, next) => {
Object.assign(req, {
executionId: nanoid(),
});

const ctx = AbyssalContext.create<IRequest>({
const ctx = AbyssalContext.create<IRequest, IResponse>({
request: req as IRequest,
response: res as IResponse,
});

asyncStorage.run(ctx, () => {
Expand All @@ -88,15 +98,44 @@ export class ExpressApplication extends AbyssalApplication<ExpressApplication> {

#applyMiddlewares(): void {
for (const middlewareInstace of this._middlewareInstances) {
this.#express.use((req, _res, next) => {
this.#express.use((req, res, next) => {
const ctx =
asyncStorage.get() ||
AbyssalContext.create<IRequest>({
AbyssalContext.create<IRequest, IResponse>({
request: req as IRequest,
response: res as IResponse,
});

middlewareInstace.use(ctx, next);
});
}
}

#applyExceptionHandlers(): void {
for (const exceptionHandler of this._exceptionHandlers) {
const catchClass = getExceptionCatchClassMetadata(
exceptionHandler.constructor,
);

this.#express.use(
(err: Error, _req: Request, _res: Response, next: INext) => {
const ctx = asyncStorage.get();

if (!catchClass || err instanceof catchClass) {
exceptionHandler.catch(err, ctx!, next);
} else {
next(err);
}
},
);
}

this.#express.use(
(err: Error, _req: Request, _res: Response, next: INext) => {
const ctx = asyncStorage.get();

this.#baseExceptionHandler.catch(err, ctx!, next);
},
);
}
}
14 changes: 14 additions & 0 deletions packages/@runners/express/src/BaseExceptionHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { httpStatusCodes, type IAbyssalExceptionHandler } from '@abyss.ts/core';

import type { IContext, INext } from './interface';

export class BaseExceptionHandler implements IAbyssalExceptionHandler {
public async catch(error: Error, ctx: IContext, _next: INext): Promise<void> {
const { response } = ctx;

response.status(httpStatusCodes.internalServerError).send({
status: httpStatusCodes.internalServerError,
message: typeof error === 'string' ? error : error.message,
});
}
}
4 changes: 2 additions & 2 deletions packages/@runners/express/src/asyncStorage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AbyssalAsyncStorage } from '@abyss.ts/core';

import type { IRequest } from './interface';
import type { IRequest, IResponse } from './interface';

export const asyncStorage = new AbyssalAsyncStorage<IRequest>();
export const asyncStorage = new AbyssalAsyncStorage<IRequest, IResponse>();
4 changes: 4 additions & 0 deletions packages/@runners/express/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ export {
Patch,
Query,
Param,
Catch,
Delete,
Inject,
Request,
Context,
Controller,
Injectable,
AbyssalContext,
httpStatusCodes,
AbyssalException,
type IAbyssalMiddleware,
type IAbyssalConfiguration,
type IAbyssalExceptionHandler,
} from '@abyss.ts/core';

export * from './Application';
Expand Down
2 changes: 1 addition & 1 deletion packages/@runners/express/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ export interface IResponse extends Response {}

export interface INext extends NextFunction {}

export interface IContext extends AbyssalContext<IRequest> {}
export interface IContext extends AbyssalContext<IRequest, IResponse> {}
10 changes: 7 additions & 3 deletions packages/@runners/express/src/utils/routeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,20 @@ export function mapRoutes(controllers: TAny[]): [string[], Router] {
combine({ joinWith: ' ' }, httpMethod.toUpperCase(), httpRoute),
);

router[httpMethod](httpRoute, async (req, res) => {
router[httpMethod](httpRoute, async (req, res, next) => {
const params = mapParameters({
controller,
propertyKey,
request: req as IRequest,
});

const result = await exec.bind(controllerInstance)(...params);
try {
const result = await exec.bind(controllerInstance)(...params);

res.send(result);
res.send(result);
} catch (err) {
next(err);
}
});
}
}
Expand Down
24 changes: 2 additions & 22 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 7c4e9df

Please sign in to comment.