Good coding habits are inseparable from exception handling, and this article will focus on how to gracefully throw errors and uniformly handle returns under the KOA framework.

preface

Good coding habits are inseparable from exception handling, and this article will focus on how to gracefully throw errors and uniformly handle returns under the KOA framework.

The body of the

Koa is an excellent NodeJS Web framework, and when we develop web projects, we can’t avoid all kinds of error handling, including Http errors and custom business logic errors.

In NodeJS, we can throw an error like this:

if (someCondition) {
  throw Error('some error')
}Copy the code

The less elegant way

HTTP error

The KOA framework provides ctx.throw(400), which makes it easy to throw HTTP errors, but what if you want to return some useful information at the same time? Here’s what you might do:

ctx.status = 400
ctx.body = {
  msg: "some params is invalid"
}Copy the code

Business logic error

So if you are developing Restful API servers, you will definitely need to define several business logic error codes and specifications, such as the following:

Code size instructions
0 ok
– 1 Server error
4001 Token expired

At the Controller level, you might want to do something like this (the constants are capitalized in the sample code, which I won’t go into later) :

router.get('/', (ctx, next) => {
  if (tokenExpire(token)) {
    const errcode = ERROR_CODE.TOKEN_EXPIRED
    ctx.body = {
      errcode,
      msg: ERROR_MSG[errcode]
    }
    return
  }
  // do something
})Copy the code

But what if you want to throw this error at the service level? There are two things you might do:

  • The first way is to define the error by defining the return value. The controller determines the return value and returns the corresponding error code, for example:

    const somefunc = async (token) => {
      const res = await tokenExpire(token)
      if (res) {
        return false
      }
      // do something
    }Copy the code
  • Second, throw an Error, catch the exception in the controller, and compare err.message to return the corresponding Error code, for example:

    const somefunc = async (token) => { const res = await tokenExpire(token) if (res) { throw Error(ERROR_MSG.TOKEN_EXPIRED)  } // do something }Copy the code

So is there a better way?

A more elegant way

Is there a more elegant way to throw an error? The answer is yes. We want a single line of code that can throw an error anywhere and be handled correctly, returning the appropriate error code and information.

This is done using koA middleware plus our custom methods that inherit from the Error constructor.

  1. Define HttpError and CustomError
function CustomError (code, msg) { Error.call(this, '') this.code = code this.msg = msg || ERROR_MSG[code] || 'unknown error' this.getCodeMsg = function () { return { code:  this.code, msg: this.msg } } } util.inherits(CustomError, Error) function HttpError (code, msg) { if (Object.values(HTTP_CODE).indexOf(code) < 0) { throw Error('not an invalid http code') } CustomError.call(this, code, msg) } util.inherits(HttpError, CustomError)Copy the code
  1. Throw an error
router.get('/HttpError', (ctx, next) => {
  throw new HttpError(HTTP_CODE.FORBIDDEN)
})
const somefunc = async (token) => {
  const res = await tokenExpire(token)
  if (res) {
    throw new CustomError(CUSTOM_CODE.SOME_CUSTOM_ERROR)
  }
  // do something
}Copy the code
  1. The KOA middleware catches the Error and returns the corresponding code, MSG
app.use((ctx, next) => { return next().catch((err) => { let code = 500 let msg = 'unknown error' if (err instanceof CustomError || err  instanceof HttpError) { const res = err.getCodeMsg() ctx.status = err instanceof HttpError ? res.code : 200 code = res.code msg = res.msg } else { console.error('err', err) } ctx.body = { code, msg } }) })Copy the code

With the above three steps, throwing an exception takes only one line of code. Throw new HttpError(http_code.forbidden) when you need to throw an HTTP error, throw new CustomError(custom_code.some_custom_error) when you need to throw a business error code. When an error is thrown, it is handled by the KOA middleware. By inheriting errors, we subdivide errors into HTTP errors and business errors to better handle Error returns.

In this way, errors and exceptions can be handled elegantly in the code

by the way

I put up a KOA scaffolding that contains the graceful error handling mentioned in this article. Welcome to star:)

Node.js performance Check