Home > Software design >  alternative to multiple try-catch blocks in a function
alternative to multiple try-catch blocks in a function

Time:02-22

Imagine we have a function like so:

async function doSomethingWithFriends() { 

  let user, friends, friendsOfFriends = null;

   try { 
       user = await getUser();
   }  catch(err){
       return [401, err]
   } 

    try {
      friends = await getFriends(user); 
    } catch (err){
       return [500, err];
    }

    try {
      friendsOfFriends = await getFriendsOfFriends(friends); 
    } catch(err){
       return [500, err]
    }

    return doFriendsOfFriends(friendsOfFriends);
} 

instead is there some established pattern to avoid this somewhat boilerplate code?

There are two problems with the above code:

  1. it's noisy
  2. we cannot use const

One solution is to only use try-catch in the caller functions, but I am wondering if there is a way to solve it all the way down.

CodePudding user response:

Are you using Expressjs or something ? Please provide more information. I will assume you are making an API.

You can create a middleware that would handle all the error in your controller. Then in your controller you only need to throw or pass the error into next middleware. Example below.

error handle middleware

export function errorHandlingController(error: ErrorRequestHandler, _req: Request, res: Response, _next: NextFunction): void {
    let errorCode: number
    if (error instanceof RequestPayloadError) {
        errorCode = 400
    } else if (error instanceof UnauthorizedError) {
        errorCode = 401
    } else if (error instanceof NotFoundError) {
        errorCode = 404
    } else {
        errorCode = 500
    }
    res.status(errorCode).json(<GeneralResponse>{
        status: responseStatus.error,
        message: error.toString()
    })
}

user controller

export function getMyProfile(_req: Request, res: Response, next: NextFunction): void {
    try {
        const user = res.locals.user
        if (!user) throw new UnauthorizedError('Author id not identified')
        res.status(200).json({
            status: responseStatus.success,
            user: user
        })
    } catch (error: unknown) {
        next(error)
    }
}

CodePudding user response:

In this case each function you can define custom exception. In doSomethingWithFriends only one try catch in used. Sample code below:

(async function doSomethingWithFriends() {


  async function getUser() {
    throw 'getUser'
  }

  async function getFriends() {
    throw 'getFriends'
  }

  async function getFriendsOfFriends() {
    throw 'getFriendsOfFriends'
  }

  let user, friends, friendsOfFriends = null;

  try {
    user = await getUser();
    friends = await getFriends(user);
    friendsOfFriends = await getFriendsOfFriends(friends);
  }  catch(err){
    console.log(err)
    if (err) {
      // custom return what you want
    }
  }

  return doFriendsOfFriends(friendsOfFriends);
}())

CodePudding user response:

The catch phrase of Promise API can be combined with switch/if statements. Something like below (did not test it for syntax err etc.):

async function doSomethingWithFriends() {    
  let errID = 0;
  return getUser()
   .then(user => (  errID,getFriends(user)))
   .then(friends => (  errID, getFriendsOfFriends(friends)))
   .then(fof => (  errID, doFriendsOfFriends(fof)))
   .catch(err => {switch (errID) {
     case 0:
       return [401, err];
     case 1:
       return [500, err];
     ...
   }});
}
  • Related