Big_Trouble
Big_Trouble

Reputation: 273

How to make node js controller not so messy?

I was making my nodeJs app and I realized that my controller is a little bit messy,so I tried to decompose the logic by creating various function but when I see the result, I have a feeling that something wrong with my code 😅😅. I mean, is it ok to use async function in another async function, or to use async functions the way I use them. Could anyone make a little code-review, I would be grateful for any help.

import { Request, Response } from "express";
import bcrypt from "bcrypt";

import Role from "../../models/Role.js";
import User from "../../models/User.js";

export default class UserControler {
    public async createUser(req: Request, res: Response): Promise<any>{
        try {
            async function getHashedPassword(password: any): Promise<string> {
                const salt: string = await bcrypt.genSalt(10);
                const hashedPassword: string = await bcrypt.hash(password, salt);
                
                return hashedPassword;
            };
            async function getDefaultRoleId(): Promise<string> {
                const [roleData, createdRole] = await Role.findOrCreate({
                    where: {
                        name: 'User',
                    },
                    defaults: {
                        name: 'User'
                    }
                });
                const roleId: string = roleData.getDataValue('_id');
                
                return roleId;
            };
            async function emailExists(email: string): Promise<boolean> {
                const user = await User.findOne({
                    where: {
                        email: email,
                    }
                });

                if (user) {
                    return true;
                } else {
                    return false;
                }
            };
            
            const _emailExists: boolean = await emailExists(req.body.email)
            if(_emailExists) return res.status(400).json({exists: true});

            await User.create({
                role: await getDefaultRoleId(),
                email: req.body.email,
                hidden: false,
                password: await getHashedPassword(req.body.password)
            }).then((data) => {
                res.json({data: data});
            })
        } catch (err: any) {
            res.status(400).json({error: err});
        }
    }
}

Upvotes: 0

Views: 423

Answers (1)

Salvino D&#39;sa
Salvino D&#39;sa

Reputation: 4506

Firstly, I would encourage you to follow the practice of creation of services. I can see from your code that you already have the controller & models in place. The only piece you're missing are services. You can move all your logic to the service file and keep your controller as thin as possible.

Sample Implementation:
// userController.ts file
import { Request, Response } from "express";
import { emailExists } from "./userService";

export default class UserController {
  public async createUser(req: Request, res: Response): Promise {
    try {
      const { email, password } = req.body;
      const _emailExists: boolean = await emailExists(email);
      if (_emailExists) return res.status(400).json({ exists: true });

      const user = await createUser(email, password);
      res.json({ data: user });
    } catch (err: any) {
      res.status(400).json({ error: err });
    }
  }
}

Now create a userService.ts file, export the methods and then reference the required ones in your main controller file.

// userService.ts
import bcrypt from "bcrypt";
import Role from "../../models/Role.js";
import User from "../../models/User.js";

export const createUser = async (
  email: string,
  password: string
): Promise<User> => {
  return User.create({
    role: await getDefaultRoleId(),
    email,
    hidden: false,
    password: await getHashedPassword(password),
  });
};

export const getHashedPassword = async (password: any): Promise<string> => {
  const salt: string = await bcrypt.genSalt(10);
  const hashedPassword: string = await bcrypt.hash(password, salt);

  return hashedPassword;
};

export const getDefaultRoleId = async (): Promise<string> => {
  const [roleData, createdRole] = await Role.findOrCreate({
    where: {
      name: "User",
    },
    defaults: {
      name: "User",
    },
  });
  const roleId: string = roleData.getDataValue("_id");
  return roleId;
};

export const emailExists = async (email: string): Promise<boolean> => {
  const user = await User.findOne({ where: { email: email } });
  if (user) return true;
  return false;
};

References:

Upvotes: 3

Related Questions