Skip to content

Commit

Permalink
feat: optimize error handler and response message
Browse files Browse the repository at this point in the history
  • Loading branch information
Roger13579 committed May 1, 2024
1 parent 80c9aae commit 6c2957a
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 69 deletions.
28 changes: 16 additions & 12 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import cookieParser from 'cookie-parser';
import cors from 'cors';
import express, { ErrorRequestHandler } from 'express';
import express from 'express';
import log4js from './config/log4js';
import path from 'path';
import morgan from 'morgan';
Expand All @@ -9,9 +9,10 @@ import connection from './config/dbConnection';
import globalMiddleware from './middleware/globalMiddleware';
import swaggerUi from 'swagger-ui-express';
import swaggerFile from './swagger-output.json';
import { DefaultException } from './utils/defaultException';
import passport from 'passport';
import { unknownRouteError } from './utils/errorHandler';
import { AppError } from './utils/errorHandler';
import { DefaultException } from './utils/defaultException';
import { CustomResponseType } from './types/customResponseType';

class App {
public app: express.Application;
Expand All @@ -29,25 +30,28 @@ class App {
// db connection
connection();
// router 處理

for (const route of router) {
this.app.use(route.getPrefix(), route.getRouters());
}
// swagger

this.app.use('/api-doc', swaggerUi.serve, swaggerUi.setup(swaggerFile));

// 查無路由
this.app.use(unknownRouteError);
this.setException(DefaultException);
this.app.use((req, res, next) => {
next(
new AppError(
CustomResponseType.NOT_SUCH_ROUTE,
404,
CustomResponseType.NOT_SUCH_ROUTE_MESSAGE,
),
);
});
this.app.use(DefaultException);
}

private initLogger() {
const logger = log4js.getLogger();
this.app.use(log4js.connectLogger(logger, { level: 'info' }));
}

private setException(handler: ErrorRequestHandler): void {
this.app.use(handler);
this.app.use(log4js.connectLogger(logger, { level: 'debug' }));
}
}

Expand Down
11 changes: 8 additions & 3 deletions src/controller/baseController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ import { ResponseObject } from '../utils/responseObject';

export abstract class BaseController {
public formatResponse(
data: any,
message: string,
status = CustomResponseType.SYSTEM_ERROR,
data: any = {},
): ResponseObject {
const options: any = { status: status };
status > '6000' ? (options.message = data) : (options.data = data);
const options: any = {
status: status,
message: message,
data: data,
};

return new ResponseObject(options);
}
}
3 changes: 2 additions & 1 deletion src/controller/userController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ class UserController extends BaseController {
user.accountType.toString(),
);
return this.formatResponse(
new SignUpVo(user, jwt),
CustomResponseType.OK_MESSAGE,
CustomResponseType.OK,
new SignUpVo(user, jwt),
);
} else {
return this.formatResponse(
Expand Down
9 changes: 2 additions & 7 deletions src/routes/baseRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,8 @@ export abstract class BaseRoute {
method
.call(this.controller, req, res, next)
.then((obj) => res.status(HttpStatus.OK).json(obj))
.catch((err: Error) =>
next(
controller.formatResponse(
err.message,
(err as any).status || HttpStatus.INTERNAL_ERROR,
),
),
.catch((err) =>
next(controller.formatResponse(err.message, (err as any).status)),
);
};
}
Expand Down
10 changes: 4 additions & 6 deletions src/service/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@ export class UserService {
const findByEmail = await UserModel.findOne({ email: email });
const findByAccount = await UserModel.findOne({ account: account });
if (findByEmail) {
const error = new Error(
this.throwError(
CustomResponseType.EMAIL_REGISTERED_MESSAGE + email,
CustomResponseType.EMAIL_REGISTERED,
);
(error as any).status = CustomResponseType.EMAIL_REGISTERED;
throw error;
} else if (findByAccount) {
const error = new Error(
this.throwError(
CustomResponseType.ACCOUNT_REGISTERED_MESSAGE + account,
CustomResponseType.ACCOUNT_REGISTERED,
);
(error as any).status = CustomResponseType.ACCOUNT_REGISTERED;
throw error;
}
return await UserModel.create(
new UserModel({
Expand Down
3 changes: 3 additions & 0 deletions src/types/customResponseType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export const enum CustomResponseType {
ACCOUNT_DISABLED = '6402',
ACCOUNT_DISABLED_MESSAGE = '此帳號已停用',

NOT_SUCH_ROUTE = '6404',
NOT_SUCH_ROUTE_MESSAGE = '無此路由資訊',

SYSTEM_ERROR = '6501',
SYSTEM_ERROR_MESSAGE = '系統錯誤',

Expand Down
15 changes: 11 additions & 4 deletions src/utils/defaultException.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { ErrorRequestHandler } from 'express';
import { CustomResponseType } from '../types/customResponseType';
export const DefaultException: ErrorRequestHandler = (err, req, res) => {
err.status = CustomResponseType.SYSTEM_ERROR;
res.status(500).json(err);
import log4js from '../config/log4js';
const logger = log4js.getLogger(`DefaultException`);

export const DefaultException: ErrorRequestHandler = (err, req, res, next) => {
logger.error(err);
err.statusCode = err.statusCode || 500;
return res.status(err.statusCode).json({
status: err.status,
message: err.message,
data: err.data,
});
};
49 changes: 13 additions & 36 deletions src/utils/errorHandler.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { Request, Response, NextFunction } from 'express';
import log4js from '../config/log4js';
const logger = log4js.getLogger(`AppError`);
import { Error } from 'mongoose';

/**
* @description - 負責將所以API的錯誤統一並回傳統一error格式
Expand All @@ -9,49 +7,28 @@ const logger = log4js.getLogger(`AppError`);
* @param {String} errMessage
*/
class AppError extends Error {
get status() {
return this._status;
}

set status(value: string | undefined) {
this._status = value;
}
get statusCode() {
return this._statusCode;
}

set statusCode(value) {
set statusCode(value: number | undefined) {
this._statusCode = value;
}
private _statusCode: number | undefined;
private _status: string | undefined;

constructor(statusCode: number, errName: string, errMessage: string) {
constructor(status: string, statusCode: number, errMessage: string) {
super(errMessage);
super.name = errName;
this.status = status;
this.statusCode = statusCode;
}
}

const globalErrorHandler = (err: Error, res: Response) => {
if (err) {
logger.info('globalErrorHandler process');
res.status(500).json({
status: 'false',
message: err.message,
error: err,
stack: err.stack,
});
}
};

const appErrorHandler = (err: AppError, res: Response) => {
if (err) {
logger.info('appErrorHandler process');
err.statusCode = err.statusCode || 500;
res.status(err.statusCode).json({
status: 'false',
message: err.message,
error: err,
stack: err.stack,
});
}
};

const unknownRouteError = (req: Request, res: Response, next: NextFunction) => {
next(new AppError(404, '40401', '無此路由資訊'));
};

export { AppError, globalErrorHandler, appErrorHandler, unknownRouteError };
export { AppError };

0 comments on commit 6c2957a

Please sign in to comment.