This article was originally published at: kapeter.com/post/32

List of articles:

  • How to Standardize the Interface Output Protocol — Eggjs Best Practices Series (Part 1)
  • How to Design Code Layering properly — Eggjs Best Practices Series (Part 2)

This is the second article in the Eggjs Best Practices series.


The early stage of the research

Before designing, let’s take a look at what a canonical interface output protocol looks like.

{
  code: "10001",
  message: "The route does not exist, please check whether the route is correct.",
  result: null,
  sysTime: 1620632378967
}
Copy the code

There may be variations in naming, but they are basically based on the following four attributes:

  • code: globally unique response code, according to which the front-end can handle the corresponding error;
  • message: Response code (code) semantic interpretation;
  • result: Used to store interface data.
  • sysTime: Optional. The current server time can be compared with the client time.

Encapsulated output function

Through investigation, we found that the standard interface output protocol has a uniform format. We can encapsulate an interface output function to unify the output.

This function can be implemented using the framework extension capabilities of Eggjs.

In the app/extend/response.js file, create two methods.

'use strict';

module.exports = {
  / * * *@description
   * @param {*} { data, status }* /
  success({ data, status }) {
    const { ctx } = this;
    ctx.body = {
      code: '0'.message: 'success'.result: data || null.sysTime: ctx.helper.now(),
    };
    ctx.status = status || 200;
  },

  / * * *@description
   * @param {*} { status, code, message, data }* /
  failure({ status, code, message, data }) {
    const { ctx } = this;
    ctx.body = {
      code: code || '1'.message: message || 'no message'.result: data || null.sysTime: ctx.helper.now(),
    };
    ctx.status = status || 200; }};Copy the code

The functions of SUCCESS and failure are basically the same. The former is used for normal response, code is 0, and message is SUCCESS. The latter is used for error responses, and code and message need to be passed in themselves. For front-end convenience, it is recommended to use 200 for all status codes (i.e., successful response).

Now we can use these two functions in our controller.

async index() {
  const { ctx, config } = this;
  ctx.response.failure(config.ERR_TYPE.NOT_EXIST_ROUTE);
}

async test() {
  const { ctx } = this;
  ctx.response.success({ data: ['test'.'test2']}); }Copy the code

The output result is shown as follows:

Careful students may also have noticed that the system time is printed using a custom function now().

This is also done through the framework’s extension capabilities, which extend the Helper classes. So you don’t have to copy code every time.

Reasonable encapsulation can greatly improve the development efficiency and optimize the code structure.

Unified management of error types

We already have a unified output protocol, isn’t that enough? The answer is no. Imagine that when the system develops to a certain stage, there will be multi-module and multi-person cooperation. If everyone maintains their own error response code (code), there may be the problem of code reuse and different types of code cannot be distinguished.

To solve this problem, it is necessary to manage the code in a unified way at the beginning of design.

In Eggjs, all configuration related data is placed in the config folder.

I created an error.js file to store the wrong configuration. Here, different prefixes are used to distinguish between different types of errors.

// config/error.js

module.exports = {
  // System error, level -10000
  UNKNOWN_ERROR: { code: '10000'.message: 'Internal server error.' }, // Unknown error
  NOT_EXIST_ROUTE: { code: '10001'.message: 'The route does not exist' }, // Route does not exist
  // Upstream system error - level 20000
  Up_SYS_TIME_OUT: { code: '20001'.message: 'Upstream system timeout.' }, // The upstream system timed out
  // The service error level is -30000
  NOT_LOGIN: { code: '30001'.message: 'Not login.' }, / / not logged in
};
Copy the code

These configurations are then injected into the system configuration.

// config/config.default.js
const ERR_TYPE = require('./error');

const userConfig = {
  ERR_TYPE,
};
Copy the code

When needed, these configurations can be obtained from app.config.err_type, as demonstrated above.

The resources

  • Eggjs document