From 62fb548ec6b0b53d549d434f30d36b02bfc62050 Mon Sep 17 00:00:00 2001 From: Sergii Mykyteiek Date: Wed, 6 Oct 2021 15:41:09 +0300 Subject: [PATCH] LT-10: Add error middleware, add logger --- src/main.ts | 3 ++ src/middleware/error.middleware.ts | 6 +++ src/modules/stack/stack.controller.spec.ts | 10 +++-- src/modules/stack/stack.controller.ts | 50 ++++++++++++++++------ src/modules/ttl/ttl.controller.spec.ts | 8 ++-- src/modules/ttl/ttl.controller.ts | 40 +++++++++++------ src/shared/logger/index.ts | 2 + src/shared/logger/logger.interfaces.ts | 9 ++++ src/shared/logger/logger.service.ts | 9 ++++ 9 files changed, 102 insertions(+), 35 deletions(-) create mode 100644 src/middleware/error.middleware.ts create mode 100644 src/shared/logger/index.ts create mode 100644 src/shared/logger/logger.interfaces.ts create mode 100644 src/shared/logger/logger.service.ts diff --git a/src/main.ts b/src/main.ts index 57acf71..4927217 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 0000000..4609de1 --- /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 b322130..8302611 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 96178c5..2e6a91b 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 1548842..bf80b84 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 5a732cb..8c0f391 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 0000000..7e387e7 --- /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 0000000..6c663f2 --- /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 0000000..3e70d11 --- /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); + } +} -- GitLab