[added] - inversify for inversion of control (IoC) container

This commit is contained in:
Swapnil Bendal
2024-12-18 13:17:41 +05:30
parent ca2831cf23
commit f67cfc4ef7
12 changed files with 100 additions and 11 deletions

View File

@@ -43,7 +43,7 @@ class App {
}
public listen(port: number): ReturnType<typeof this.app.listen> {
return this.app.listen(port, () => {
return this.app.listen(port, () => {
logger.info(`Server listening on port ${config.port}`);
logger.info(`Environment :- ${config.env}`);
})

View File

@@ -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;
}

View File

@@ -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<boolean> {
logger.debug("Sending mail...", { to, subject, body });
return true;
}
}

View File

@@ -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<boolean> {
logger.debug("Message send ...", product);
return true;
}
}

View File

@@ -1,4 +1,4 @@
import "reflect-metadata"
import app from "./app";
import config from "./config/config";
import { AppDataSource } from "./config/data-source";

View File

@@ -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<Product> {
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<Product> {
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<Product[]> {
return await this.repository.find(limit, offset)

View File

@@ -0,0 +1,3 @@
export interface IMailer {
SendMail(to: string, subject: string, body: unknown): Promise<boolean>;
}

View File

@@ -0,0 +1,3 @@
export interface IMessageBroker {
NotifyToPromotionService(product: unknown): Promise<boolean>;
}

View File

@@ -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<Product>;

View File

@@ -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<IProductRepository>(INTERFACE_TYPE.ProductRepository).to(ProductRepository);
container.bind<IProductInteractor>(INTERFACE_TYPE.ProductInteractor).to(ProductInteractor);
container.bind<IMailer>(INTERFACE_TYPE.Mailer).to(Mailer);
container.bind<IMessageBroker>(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<ProductController>(INTERFACE_TYPE.ProductController);
router.post('/', productController.onCreateProduct.bind(productController));
router.get('/', productController.onGetProducts.bind(productController));
router.patch('/:id', productController.onUpdateStock.bind(productController));

View File

@@ -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"),
}

5
src/utils/index.ts Normal file
View File

@@ -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";