From f67cfc4ef7b60a431276078f6691ba0d435200c6 Mon Sep 17 00:00:00 2001 From: Swapnil Bendal <84583651+Swapnil155@users.noreply.github.com> Date: Wed, 18 Dec 2024 13:17:41 +0530 Subject: [PATCH] [added] - inversify for inversion of control (IoC) container --- src/app.ts | 2 +- src/controllers/productController.ts | 8 +++++-- src/external-libraries/mailer.ts | 11 ++++++++++ src/external-libraries/messageBroker.ts | 12 ++++++++++ src/index.ts | 2 +- src/interactors/productInteractor.ts | 27 +++++++++++++++++++---- src/interfaces/IMailer.ts | 3 +++ src/interfaces/IMessageBroker.ts | 3 +++ src/repositories/productRepository.ts | 2 ++ src/routes/productRoutes.ts | 29 ++++++++++++++++++++++--- src/utils/constant/appConstant.ts | 7 ++++++ src/utils/index.ts | 5 +++++ 12 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 src/external-libraries/mailer.ts create mode 100644 src/external-libraries/messageBroker.ts create mode 100644 src/interfaces/IMailer.ts create mode 100644 src/interfaces/IMessageBroker.ts create mode 100644 src/utils/constant/appConstant.ts create mode 100644 src/utils/index.ts diff --git a/src/app.ts b/src/app.ts index 35c5af1..e2e4a8f 100644 --- a/src/app.ts +++ b/src/app.ts @@ -43,7 +43,7 @@ class App { } public listen(port: number): ReturnType { - return this.app.listen(port, () => { + return this.app.listen(port, () => { logger.info(`Server listening on port ${config.port}`); logger.info(`Environment :- ${config.env}`); }) diff --git a/src/controllers/productController.ts b/src/controllers/productController.ts index 379d302..2d41769 100644 --- a/src/controllers/productController.ts +++ b/src/controllers/productController.ts @@ -2,11 +2,15 @@ import { Request, Response } from 'express'; import { IProductInteractor } from '../interfaces/IProductInteractor'; import ApiResponse from '../utils/helper/ApiResponse'; import { AsyncHandler } from '../utils/handler/async.handler'; - +import { inject, injectable } from 'inversify'; +import { INTERFACE_TYPE } from '../utils'; +@injectable() export class ProductController { private interactor: IProductInteractor; - constructor(interactor: IProductInteractor) { + constructor( + @inject(INTERFACE_TYPE.ProductInteractor) interactor: IProductInteractor + ) { this.interactor = interactor; } diff --git a/src/external-libraries/mailer.ts b/src/external-libraries/mailer.ts new file mode 100644 index 0000000..bf6f755 --- /dev/null +++ b/src/external-libraries/mailer.ts @@ -0,0 +1,11 @@ +import { injectable } from "inversify"; +import logger from "../config/logger"; +import { IMailer } from "../interfaces/IMailer"; + +@injectable() +export class Mailer implements IMailer { + async SendMail(to: string, subject: string, body: unknown): Promise { + logger.debug("Sending mail...", { to, subject, body }); + return true; + } +} diff --git a/src/external-libraries/messageBroker.ts b/src/external-libraries/messageBroker.ts new file mode 100644 index 0000000..dfe6e41 --- /dev/null +++ b/src/external-libraries/messageBroker.ts @@ -0,0 +1,12 @@ +import { injectable } from "inversify"; +import logger from "../config/logger"; +import { IMessageBroker } from "../interfaces/IMessageBroker"; + +@injectable() +export class MessageBroker implements IMessageBroker { + async NotifyToPromotionService(product: unknown): Promise { + logger.debug("Message send ...", product); + return true; + } + +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 88344d0..e09475f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ - +import "reflect-metadata" import app from "./app"; import config from "./config/config"; import { AppDataSource } from "./config/data-source"; diff --git a/src/interactors/productInteractor.ts b/src/interactors/productInteractor.ts index f00e0ec..77ece0e 100644 --- a/src/interactors/productInteractor.ts +++ b/src/interactors/productInteractor.ts @@ -1,20 +1,39 @@ +import { IMailer } from "../interfaces/IMailer"; import { Product } from "../entities/Product"; import { IProductInteractor } from "../interfaces/IProductInteractor"; import { IProductRepository } from "../interfaces/IProductRepository"; +import { IMessageBroker } from "../interfaces/IMessageBroker"; +import { inject, injectable } from "inversify"; +import { INTERFACE_TYPE } from "../utils"; +@injectable() export class ProductInteractor implements IProductInteractor { private repository: IProductRepository + private mailer: IMailer + private broker: IMessageBroker - constructor(respository: IProductRepository) { - this.repository = respository + constructor( + @inject(INTERFACE_TYPE.ProductRepository) repository: IProductRepository, + @inject(INTERFACE_TYPE.Mailer) mailer: IMailer, + @inject(INTERFACE_TYPE.MessageBroker) broker: IMessageBroker + ) { + this.repository = repository + this.mailer = mailer + this.broker = broker } async createProduct(input: never): Promise { - return await this.repository.create(input) + const data = await this.repository.create(input) + // Do something notify promotion message + await this.broker.NotifyToPromotionService(data) + return data } async updateStock(id: number, stock: number): Promise { - return await this.repository.update(id, { stock: stock }) + const data = await this.repository.update(id, { stock: stock }) + // Do some update Admin update a stock + await this.mailer.SendMail("someone@gmail.com", "Update Stock", data) + return data } async getProducts(limit: number, offset: number): Promise { return await this.repository.find(limit, offset) diff --git a/src/interfaces/IMailer.ts b/src/interfaces/IMailer.ts new file mode 100644 index 0000000..8884bdf --- /dev/null +++ b/src/interfaces/IMailer.ts @@ -0,0 +1,3 @@ +export interface IMailer { + SendMail(to: string, subject: string, body: unknown): Promise; +} \ No newline at end of file diff --git a/src/interfaces/IMessageBroker.ts b/src/interfaces/IMessageBroker.ts new file mode 100644 index 0000000..5d0581b --- /dev/null +++ b/src/interfaces/IMessageBroker.ts @@ -0,0 +1,3 @@ +export interface IMessageBroker { + NotifyToPromotionService(product: unknown): Promise; +} \ No newline at end of file diff --git a/src/repositories/productRepository.ts b/src/repositories/productRepository.ts index b29d5e3..25b1482 100644 --- a/src/repositories/productRepository.ts +++ b/src/repositories/productRepository.ts @@ -3,7 +3,9 @@ import { AppDataSource } from "../config/data-source"; import { Product } from "../entities/Product"; import { IProductRepository } from "../interfaces/IProductRepository"; import ApiError from "../utils/helper/ApiError"; +import { injectable } from "inversify"; +@injectable() export class ProductRepository implements IProductRepository { private readonly productRepository: Repository; diff --git a/src/routes/productRoutes.ts b/src/routes/productRoutes.ts index d827e4c..4687845 100644 --- a/src/routes/productRoutes.ts +++ b/src/routes/productRoutes.ts @@ -3,13 +3,36 @@ import { ProductController } from '../controllers/productController'; import { ProductRepository } from '../repositories/productRepository'; import { ProductInteractor } from '../interactors/productInteractor'; import { IProductInteractor } from '../interfaces/IProductInteractor'; +import { Mailer } from '../external-libraries/mailer'; +import { MessageBroker } from '../external-libraries/messageBroker'; +import { Container } from 'inversify'; +import { IProductRepository } from '../interfaces/IProductRepository'; +import { INTERFACE_TYPE } from '../utils'; +import { IMailer } from '../interfaces/IMailer'; +import { IMessageBroker } from '../interfaces/IMessageBroker'; + +/** + const repository = new ProductRepository() + const mailer = new Mailer(); + const broker = new MessageBroker() + const interactor: IProductInteractor = new ProductInteractor(repository, mailer, broker) + const productController = new ProductController(interactor); + + */ + +const container = new Container(); + +container.bind(INTERFACE_TYPE.ProductRepository).to(ProductRepository); +container.bind(INTERFACE_TYPE.ProductInteractor).to(ProductInteractor); +container.bind(INTERFACE_TYPE.Mailer).to(Mailer); +container.bind(INTERFACE_TYPE.MessageBroker).to(MessageBroker); +container.bind(INTERFACE_TYPE.ProductController).to(ProductController); -const repository = new ProductRepository() -const interactor: IProductInteractor = new ProductInteractor(repository) -const productController = new ProductController(interactor); const router = express.Router(); +const productController = container.get(INTERFACE_TYPE.ProductController); + router.post('/', productController.onCreateProduct.bind(productController)); router.get('/', productController.onGetProducts.bind(productController)); router.patch('/:id', productController.onUpdateStock.bind(productController)); diff --git a/src/utils/constant/appConstant.ts b/src/utils/constant/appConstant.ts new file mode 100644 index 0000000..14b2632 --- /dev/null +++ b/src/utils/constant/appConstant.ts @@ -0,0 +1,7 @@ +export const INTERFACE_TYPE = { + ProductRepository: Symbol.for("ProductRepository"), + ProductInteractor: Symbol.for("ProductInteractor"), + ProductController: Symbol.for("ProductController"), + Mailer: Symbol.for("Mailer"), + MessageBroker: Symbol.for("MessageBroker"), +} \ No newline at end of file diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..7c7a8a8 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,5 @@ +export * from "./handler/async.handler"; +export * from "./handler/pick.handler"; +export * from "./helper/ApiError"; +export * from "./helper/ApiResponse" +export * from "./constant/appConstant"; \ No newline at end of file