0

I have a problem trying to access to "service" property inside a controller method. I receive the error "Cannot read properties of undefined (reading "service")".

I can't understand why because within my service I have declared a property in the same way and it works.

this is my service:

export default class StaffService {
  private daoStaff: StaffDao;

  constructor() {
    this.daoStaff = new StaffDao();
  }


  async login(username: string, password: string) {
    const checkUser = await this.daoStaff.findByUsername(username);
    if (!checkUser) throw new Error("INVALID_CREDENTIALS");

    return await this.daoStaff.login(username, password);
  }
  
  }

when I run tests on the service it works perfectly.

this is my controller:

export default class StaffController {
  private service: StaffService;

  constructor() {
    this.service = new StaffService();
  }


 async login (req: Request, res: Response){
    try {
      const { username, password } = req.body;

      const resService = await this.service.login(username, password);

      return res
        .status(200)
        .json(new ResponseEntity(200, "LOGIN_SUCCESSFULLY", resService));
    } catch (e: unknown) {
      if (e instanceof Error) {
        switch (e.message) {
          case "INVALID_CREDENTIALS":
            return res
              .status(400)
              .json(new ResponseEntity(400, e.message, null));
          default:
            return res
              .status(500)
              .json(new ResponseEntity(500, e.message, null));
        }
      }
    }
  };
  
  }

when I run tests on the controller I get the error "Cannot read properties of undefined (reading "service")".

I have tried some solutions such as:

Converting the method to an arrow function and it works, but I don't know if this is a good practice.

login = async (req: Request, res: Response) => {
    try {
      const { username, password } = req.body;

      const resService = await this.service.login(username, password);

      return res
        .status(200)
        .json(new ResponseEntity(200, "LOGIN_SUCCESSFULLY", resService));
    } catch (e: unknown) {
      if (e instanceof Error) {
        switch (e.message) {
          case "INVALID_CREDENTIALS":
            return res
              .status(400)
              .json(new ResponseEntity(400, e.message, null));
          default:
            return res
              .status(500)
              .json(new ResponseEntity(500, e.message, null));
        }
      }
    }
  };

Another solution that worked was to do a .bind() in the constructor() for the method and that also worked, but my controller has more than 10 methods and I would have to bin each of the methods and I don't know if that is good practice either.

What is the best solution to this problem? What am I doing wrong?

  • my tests give error because it cannot login and in the console I get the error "Cannot read properties of undefined (reading "service")", when I try to access the endpoint through postman I get the same message. – Franco Rodriguez Aug 07 '23 at 13:50
  • How exactly are you *calling* the `login` function…? See the duplicate linked above, that's probably your issue. – deceze Aug 07 '23 at 13:51
  • In my router a call the method like this: const controller = new StaffController(); staffRouter.post("/login", controller.login); I have tried converting the method into an arrow function and it works, but I don't know if it is a good practice, I read in several articles that its use is discouraged but I don't know why. I am a beginner in this. – Franco Rodriguez Aug 07 '23 at 13:59
  • Yes, `staffRouter.post("/login", controller.login)` is exactly the problem, where you're losing the `this` context. Read the duplicate linked above. – deceze Aug 07 '23 at 14:13
  • Okay, thanks for your help! – Franco Rodriguez Aug 07 '23 at 15:46

0 Answers0