skip to Main Content

I am using an AsyncHandler wrapper function to catch my errors in my controller and service layer.
I am using next() parameter to raise an error, and then catch it in my global error handler.
My global error handler is executing but my controller is also returning, even though it should haven’t return anything after error is thrown.
My Controller layer:

const categoryCtrl = {
  create: asyncHandler( async (req, res, next) => {

    const data = await CategoryService.createCategory("", 4, next)

   return  successResponse({res, data:data, msg:"Category created Successfully"})

  }),
  getAll: async (req, res, next) => {},
  getById: async (req, res, next) => {},
  delete: async (req, res, next) => {},
  update: async (req, res, next) => {},
};

My service layer:

const categoryService = {
  createCategory: async (data, x, next) => {
  
      if (data === "") {
        console.log("condition");
        const err = new CustomError(404, "Wrong input");
        return next(err);
      } else {
        return data;
      }

  },
};

My asyncHandler :

const asyncHandler = (func) => {
  return  (req, res, next) => {
    try {
       func(req, res, next)

    } catch (error) {
      next(error)

    }


  };
};

My successReponse:

module.exports  = ({res, msg, data}) => {

    return res.status(200).json({msg:msg, data: data})

}

I have tried to use throw, but I am trying to avoid try-catch block in my controller layer and service layer and raise error only throw using next() parameter.

3

Answers


  1. It looks like the asyncHandler is not correctly handling the asynchronous nature of the operations inside it. Specifically, it does not await the completion of the func it wraps.
    You can modify your asyncHandler to properly handle asynchronous functions like this

    const asyncHandler = (func) => {
      return (req, res, next) => {
        func(req, res, next).catch(next);
      };
    };
    

    This asyncHandler now explicitly handles the promise returned by the func.

    Login or Signup to reply.
  2. Update your controller by this

    const categoryCtrl = { create: asyncHandler(async (req, res, next)
    => {
    const data = await CategoryService.createCategory("", 4, next);
    if (data instanceof Error) {
    return;
    }
    return successResponse({ res, data: data, msg: "Category created Successfully" }); }), // your other methods will reside here };

    Update your service layer by this

    const categoryService = { createCategory: async (data, x, next) => {
    if (data === "") {
    console.log("condition");
    const err = new CustomError(404, "Wrong input");
    next(err);
    return err;
    } else {
    return data;
    } }, // your other methods reside here. }; “

    Login or Signup to reply.
  3. I have tried to use throw, but I am trying to avoid trycatch block in my controller layer and service layer and raise error only throw using next() parameter.

    That would have been the correct approach. If you want to use exceptions, you actually have to use them! Notice that you don’t actually need a try/catch in your controller, that’s precisely what the asyncHandler is doing for you. Notice that if you weren’t using exceptions, you would have to return an error code (e.g. null instead of a data object) from the service, and explicitly check that in your controller so that you return successResponse conditionally. You don’t want that – only exceptions can achieve the goal of not requiring extra syntax in intermediate layers between the service and asyncHandler.

    // Controller:
    const categoryCtrl = {
      create: asyncHandler(async(req, res) => {
        const data = await CategoryService.createCategory("", 4, next)
        return successResponse({res, data, msg: "Category created Successfully"});
      }),
      getAll: asyncHandler(async(req, res) => {}),
      getById: asyncHandler(async(req, res) => {}),
      delete: asyncHandler(async(req, res) => {}),
      update: asyncHandler(async(req, res) => {}),
    };
    
    // Service layer:
    const categoryService = {
      async createCategory(data, x) {
        if (data === "") {
          console.log("condition");
          throw new CustomError(404, "Wrong input");
        } else {
          return data;
        }
      },
    };
    

    Using

    const asyncHandler = (func) => (req, res, next) => {
      func(req, res, next).catch(next);
    };
    // or
    const asyncHandler = (func) => async (req, res) => {
      try {
        await func(req, res)
      } catch (error) {
        next(error);
      }
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search