diff --git a/src/main.ts b/src/main.ts index 57acf71d47d6e5d921a126351a424cf718e3508f..49272179841ae2ae0bf843f6c20c728a776723fd 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,6 +6,7 @@ const morgan = require('morgan'); import { getConfig } from './config'; import { stackRouter } from './modules/stack/stack.router'; import { ttlRouter } from './modules/ttl/ttl.router'; +import { errorMiddleware } from './middleware/error.middleware'; const app = express(); @@ -18,6 +19,8 @@ function start() { app.use('/stack', stackRouter); app.use('/ttl', ttlRouter); + app.use(errorMiddleware); + app.listen(config.PORT, () => { // eslint-disable-next-line no-console console.log(`Application started on port ${config.PORT}!`); diff --git a/src/middleware/error.middleware.ts b/src/middleware/error.middleware.ts new file mode 100644 index 0000000000000000000000000000000000000000..4609de130dd029f9e0713efeabfc6843374277e2 --- /dev/null +++ b/src/middleware/error.middleware.ts @@ -0,0 +1,6 @@ +import { Response, Request, NextFunction} from 'express'; + +export const errorMiddleware = (error: Error, req: Request, res: Response, next: NextFunction) => { + delete error.stack; + next(error); +}; diff --git a/src/modules/stack/stack.controller.spec.ts b/src/modules/stack/stack.controller.spec.ts index b32213039bdb890e6890752d5e1b7f78888e26fc..830261134dda329d6cd7919b405c5e1e3be818d5 100644 --- a/src/modules/stack/stack.controller.spec.ts +++ b/src/modules/stack/stack.controller.spec.ts @@ -11,6 +11,8 @@ const mockResponse = { send: jest.fn(), }; +const mockNextFunction = jest.fn(); + describe('StackController', () => { let stackController; let validateService; @@ -36,7 +38,7 @@ describe('StackController', () => { jest.spyOn(stackService, 'add').mockImplementation(() => {}); jest.spyOn(validateService, 'validateBody').mockResolvedValue(errors); - await stackController.add(mockRequest, mockResponse); + await stackController.add(mockRequest, mockResponse, mockNextFunction); expect(stackService.add).not.toBeCalled(); expect(mockResponse.status).toBeCalledWith(StatusCodes.BAD_REQUEST); @@ -54,7 +56,7 @@ describe('StackController', () => { jest.spyOn(stackService, 'add').mockImplementation(() => response); jest.spyOn(validateService, 'validateBody').mockResolvedValue(errors); - await stackController.add(mockRequest, mockResponse); + await stackController.add(mockRequest, mockResponse, mockNextFunction); expect(stackService.add).toBeCalledWith(mockRequest.body); expect(mockResponse.status).toBeCalledWith(StatusCodes.CREATED); @@ -71,7 +73,7 @@ describe('StackController', () => { jest.spyOn(stackService, 'isEmpty').mockImplementation(() => true); jest.spyOn(stackService, 'get').mockImplementation(() => {}); - await stackController.get(mockRequest, mockResponse); + await stackController.get(mockRequest, mockResponse, mockNextFunction); expect(mockResponse.status).toBeCalledWith(StatusCodes.NO_CONTENT); expect(mockResponse.send).toBeCalledTimes(1); @@ -88,7 +90,7 @@ describe('StackController', () => { jest.spyOn(stackService, 'isEmpty').mockImplementation(() => false); jest.spyOn(stackService, 'get').mockImplementation(() => response); - await stackController.get(mockRequest, mockResponse); + await stackController.get(mockRequest, mockResponse, mockNextFunction); expect(mockResponse.status).toBeCalledWith(StatusCodes.OK_RESPONSE); expect(mockResponse.send).not.toBeCalled(); diff --git a/src/modules/stack/stack.controller.ts b/src/modules/stack/stack.controller.ts index 96178c5c736f06d997ff3cd1e85d90145a702d1c..2e6a91bdd77a22aab2558242015265cec16cd7f4 100644 --- a/src/modules/stack/stack.controller.ts +++ b/src/modules/stack/stack.controller.ts @@ -1,8 +1,9 @@ -import { Request, Response } from 'express'; +import { NextFunction, Request, Response } from 'express'; import { Service } from 'typedi'; import { StackService } from './stack.service'; import { StackResponse } from './stack.dto'; import { StackValidationService } from './validation'; +import { LoggerService } from '../../shared/logger'; import { StatusCodes } from '../../common/constants'; @Service() @@ -10,26 +11,47 @@ export class StackController { constructor( private readonly stackService: StackService, private readonly validationService: StackValidationService, + private readonly logger: LoggerService, ) {} - async add(req: Request, res: Response): Promise> { - const errors = await this.validationService.validateBody(req.body); - if (errors.length > 0) { - return res.status(StatusCodes.BAD_REQUEST).send({ errors }); - } + async add(req: Request, res: Response, next: NextFunction): Promise> { + try { + const errors = await this.validationService.validateBody(req.body); + if (errors.length > 0) { + return res.status(StatusCodes.BAD_REQUEST).send({ errors }); + } - const result = this.stackService.add(req.body); + const result = this.stackService.add(req.body); - return res.status(StatusCodes.CREATED).json(result); - } + return res.status(StatusCodes.CREATED).json(result); + } catch (e) { + this.logger.error({ + placement: `[${this.constructor.name}].add`, + error: e, + arguments: Array.from(arguments), + }); - async get(req: Request, res: Response): Promise> { - if (this.stackService.isEmpty()) { - return res.status(StatusCodes.NO_CONTENT).send(); + next(e); } + } - const result = this.stackService.get(); + async get(req: Request, res: Response, next: NextFunction): Promise> { + try { + if (this.stackService.isEmpty()) { + return res.status(StatusCodes.NO_CONTENT).send(); + } - return res.status(StatusCodes.OK_RESPONSE).json(result); + const result = this.stackService.get(); + + return res.status(StatusCodes.OK_RESPONSE).json(result); + } catch (e) { + this.logger.error({ + placement: `[${this.constructor.name}].get`, + error: e, + arguments: Array.from(arguments), + }); + + next(e); + } } } diff --git a/src/modules/ttl/ttl.controller.spec.ts b/src/modules/ttl/ttl.controller.spec.ts index 15488422db58165f3dc182385ce09b856c72c957..bf80b8488a395d472c933886625272cec37534f1 100644 --- a/src/modules/ttl/ttl.controller.spec.ts +++ b/src/modules/ttl/ttl.controller.spec.ts @@ -11,6 +11,8 @@ const mockResponse = { send: jest.fn(), }; +const mockNextFunction = jest.fn(); + describe('TtlController', () => { let ttlController: TtlController; let validateService: TtlValidationService; @@ -37,7 +39,7 @@ describe('TtlController', () => { jest.spyOn(ttlService, 'get').mockImplementation(() => ({}) as any); jest.spyOn(ttlService, 'add').mockImplementation(() => ({}) as any); - await ttlController.add(mockRequest, mockResponse); + await ttlController.add(mockRequest, mockResponse, mockNextFunction); expect(mockResponse.status).toBeCalledWith(StatusCodes.BAD_REQUEST); expect(mockResponse.send).toBeCalledWith({ errors }); @@ -57,7 +59,7 @@ describe('TtlController', () => { jest.spyOn(ttlService, 'get').mockImplementation(() => ({}) as any); jest.spyOn(ttlService, 'add').mockImplementation(() => ({}) as any); - await ttlController.add(mockRequest, mockResponse); + await ttlController.add(mockRequest, mockResponse, mockNextFunction); expect(mockResponse.status).toBeCalledWith(StatusCodes.CONFLICT); expect(mockResponse.send).not.toBeCalled(); @@ -77,7 +79,7 @@ describe('TtlController', () => { jest.spyOn(ttlService, 'get').mockImplementation(() => null as any); jest.spyOn(ttlService, 'add').mockImplementation(() => result); - await ttlController.add(mockRequest, mockResponse); + await ttlController.add(mockRequest, mockResponse, mockNextFunction); expect(mockResponse.status).toBeCalledWith(StatusCodes.CREATED); expect(mockResponse.send).not.toBeCalled(); diff --git a/src/modules/ttl/ttl.controller.ts b/src/modules/ttl/ttl.controller.ts index 5a732cb441d6ea0c15ee4c647f5387795d7475b2..8c0f391bcf04575c2b75cbd546d52731c4892f0e 100644 --- a/src/modules/ttl/ttl.controller.ts +++ b/src/modules/ttl/ttl.controller.ts @@ -1,8 +1,9 @@ -import { Request, Response } from 'express'; +import { NextFunction, Request, Response } from 'express'; import { Service } from 'typedi'; import { TtlService } from './ttl.service'; import { TtlResponse } from './ttl.dto'; import { TtlValidationService } from './validation'; +import { LoggerService } from '../../shared/logger'; import { StatusCodes } from '../../common/constants'; @Service() @@ -10,22 +11,33 @@ export class TtlController { constructor( private readonly ttlService: TtlService, private readonly validationService: TtlValidationService, + private readonly logger: LoggerService, ) {} - async add(req: Request, res: Response): Promise> { - const errors = await this.validationService.validateBody(req.body); - if (errors.length > 0) { - return res.status(StatusCodes.BAD_REQUEST).send({ errors }); + async add(req: Request, res: Response, next: NextFunction): Promise> { + try { + const errors = await this.validationService.validateBody(req.body); + if (errors.length > 0) { + return res.status(StatusCodes.BAD_REQUEST).send({ errors }); + } + + const data = this.ttlService.get(req.body.key); + if (data) { + return res.status(StatusCodes.CONFLICT).json({ message: 'Key already exist' }); + } + + const result = this.ttlService.add(req.body); + + return res.status(StatusCodes.CREATED).json(result); + } catch (e) { + this.logger.error({ + placement: `[${this.constructor.name}].add`, + error: e, + arguments: Array.from([req.body]), + }); + + next(e); } - - const data = this.ttlService.get(req.body.key); - if (data) { - return res.status(StatusCodes.CONFLICT).json({ message: 'Key already exist' }); - } - - const result = this.ttlService.add(req.body); - - return res.status(StatusCodes.CREATED).json(result); } get(req: Request, res: Response): Response { diff --git a/src/shared/logger/index.ts b/src/shared/logger/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..7e387e79695cd169dd32c5413187cfc6e788f8ae --- /dev/null +++ b/src/shared/logger/index.ts @@ -0,0 +1,2 @@ +export * from './logger.service'; +export * from './logger.interfaces'; diff --git a/src/shared/logger/logger.interfaces.ts b/src/shared/logger/logger.interfaces.ts new file mode 100644 index 0000000000000000000000000000000000000000..6c663f2f3064387a58baa3b594ccec6f383245c3 --- /dev/null +++ b/src/shared/logger/logger.interfaces.ts @@ -0,0 +1,9 @@ +export type LoggerMessage = string | { + placement: string; + arguments?: any; + error?: Error | string; +}; + +export interface ILoggerError { + error(message: LoggerMessage): void; +} \ No newline at end of file diff --git a/src/shared/logger/logger.service.ts b/src/shared/logger/logger.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..3e70d115b511c54ac9c1dcd7b6ac5a835805d496 --- /dev/null +++ b/src/shared/logger/logger.service.ts @@ -0,0 +1,9 @@ +import { Service } from 'typedi'; +import { ILoggerError, LoggerMessage } from './logger.interfaces'; + +@Service() +export class LoggerService implements ILoggerError { + error(message: LoggerMessage) { + console.log(message); + } +}