Dependency Injection with typescript and express using classes

Viewed 1864

How we can use the concept of dependency injection in route file and added in server file?

I tried to use dependency injection in my node project but I don't think that I am on the right path. I am trying to inject my UserService into my AppRouter. My registration method was previously static but I changed it to a public method because a static member does not allow me to inject the dependency.

First of all this.userService.UserRegistrationService is showing me error undefined. Please suggest the right way to do this as I am new to express and node.

Route File

import express from 'express';
import bodyParser = require('body-parser');
import { API } from ".././utilities/api";
import UserService from '../api/services/UserService';
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
import validationMw from '../api/middlewares/request_validation';
import UserDao from '../api/requests/userDto';
let cors = require('cors');
//let bodyParser = require('body-parser');
 
class AppRouter {

  private userService: UserService;
  public router: express.Router;
  public userObj: any;

  constructor(userService: UserService) {
    this.router = express();
    this.router.use(cors());
    this.AddMiddlewares();
    this.AddRoutes();
   
    this.userService =  userService;
  }

  // Add all middlewares here that will get request before routes.
  AddMiddlewares(): void { //  Used to parse req.body into json object

    this.router.use(bodyParser.json());
    this.router.use(bodyParser.urlencoded({ extended: false }));
    //this.router.use(LogsService.LogRequest);
  }

  AddRoutes(): void {
    console.log(API.RegistrationEmployee);
    this.router.post(API.RegistrationEmployee, this.userService.UserRegistrationService);
  }
}

export default new AppRouter(new UserService).router;

User Services Class

import { Request, Response } from "express-serve-static-core";
import { isNullOrUndefined, isNull } from "util";
import { logger } from "../../utilities/logger";
import UserController from "../controllers/userController";
import { ProjectConstants, ErrorCodes } from "../../utilities/config";
import {
  ReasonPhrases,
  StatusCodes,
  getReasonPhrase,
  getStatusCode,
} from "http-status-codes";
import ResponseService from "../services/ResponseService";

export default class UserService {

  private userController: UserController;
  
  constructor(userController?: UserController) {
      this.userController = userController;
  }  

  public async UserRegistrationService(req: Request, res: Response) {
    console.log(434);
    // UtilityMethods.ConsoleLog("UserRegisterService - BODY", req.body);
    logger.info("UserRegistration- function call " + JSON.stringify(req.body));
    
    await this.userController.registration(req.body)
      .then((data: any) => {
        // UtilityMethods.ConsoleJSON("03 GetCategoryService", data);
        ResponseService.SendSucessResponse(req, res, data, ErrorCodes.OK);
      })
      .catch(function (err: any) {
        ResponseService.SendErrorResponse(req, res, err);
      });
  }
}
1 Answers

You have designed some of these classes to take dependencies in their constructors, but you need to make sure that you are providing the dependencies when you call new.

You are missing the parentheses after UserService in this line new AppRouter(new UserService).router. It needs to be new UserService() in order to fix the syntax error. But you will still have runtime errors.

This block of code right here is a problem:

class UserService {
    private userController: UserController;

    constructor(userController?: UserController) {
        this.userController = userController;
    }

private userController: UserController means that this.userController must always be a UserController. But constructor(userController?: UserController) means that you can construct it with a UserController or without one. If you call new UserService() with no arguments, then this.userController is undefined and that's not ok. Doing things like this await this.userController.registration(req.body) will give you errors if this.userController is undefined.

In order for your UserService to work, you must provide a UserController argument to the constructor.

We change the constructor so that it is no longer optional:

    constructor(userController: UserController) {

But now we have a problem with the line where you create the AppRouter because you need to be providing a UserController.

This won't work:

export default new AppRouter(new UserService()).router;

I'm not sure how you instantiate the UserController (does it require any arguments?), so this might not be right. But it should look something like this:

const userController = new UserController();

export default new AppRouter(new UserService(userController)).router;
Related