2

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/up.

2
  • You can write multiple awaits in a single try catch block. so your catch block will receive the error if any of the above await fails. Commented Feb 22, 2022 at 7:18
  • @HyunjuneKim From the code, however, it looks like the failure of different awaited functions shall correspond to different error messages and HTTP status codes. You may lose the ability to differentiate different failures when putting everything in the same try block. Commented Feb 22, 2022 at 7:21

3 Answers 3

1

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)
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

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);
}())

2 Comments

A String is not an Error. Other than that, it isn’t necessarily the case that each of these async functions has a unique, easily identifiable error message.
this is demo code, you should throw custom error
1

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];
     ...
   }});
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.