I developed a software based on egg JS back-end scaffold

background

Previously based on egg JS has developed several projects. It is found that each project has functions such as configuration file, database connection operation, data model definition, wechat login authorization processing, etc. when making A new project, it will always copy the previous project to delete and modify. Sometimes A practical function is added to project A and A cool tool function is added to project B, but it is forgotten later, There is no place for unified sedimentation, so A scaffold is made, which can be used out of the box for new project development and facilitate technical sedimentation.

location

Based on egg JS encapsulates a layer, aggregating common functions together, closer to the business, if egg JS is noodles, so this back-end scaffold is noodles.

Function introduction

modularFunction introductionspeed of progress
Database operationThe built-in ORM egg serialize plug-in is used as the database operation library, which can be adapted to Postgres, MySQL, MariaDB and SQLite databases
Interface routing configurationThe built-in egg router plus plug-in solves the problem of routing namespace
Automatically generate interface documentsBuilt in egg swagger doc plug-in, write interface notes according to the contract, and then automatically generate interface use documents
Field verificationThe built-in egg validate plus plug-in is used as field verification, which can be used alone or in combination with the egg swagger doc plug-in. It not only automatically generates interface documents, but also realizes field verification
Multi environment configurationBuilt in local development environment, test environment and production environment configuration, switching and expansion are very convenient
Cross domain configurationDifferent cross domain configurations are set in multiple environments to meet the different demands of cross domain strategies in each environment
exception handlingUniformly encapsulate and handle the errors thrown, and do not throw the errors directly to the front end, so as to improve the security and better front-end use experience
Tool libraryIt encapsulates common tool functions such as menu tree processing, version number comparison and uid generation, which makes development more convenient
unit testing Complete unit tests make the code more robust
Wechat applet loginBuilt in the whole process of authorized login and obtaining mobile phone number of wechat applet, which can be seamlessly connected with wechat applet
eslintStrict and complete eslint rules are built in to ensure code specification and more efficient collaborative development

Project structure

.
├── LICENSE
├── README.md              # Please read me before you get into trouble
├── app                    # Main program code directory
│   ├── contract           # Data structure required for automatic generation of interface documents
│   ├── controller         # controller
│   ├── extend             # Framework extension
│   ├── middleware         # middleware 
│   ├── model              # data model
│   ├── public             # Public static resources
│   ├── router.js          # Routing configuration
│   └── service            # service
├── app.js                 # entrance
├── appveyor.yml
├── config
│   ├── config.default.js  # Default configuration, including customized application configuration, security policy, cookie, cross domain, permission, etc
│   ├── config.local.js    # Configuration items specific to the local environment
│   ├── config.prod.js     # Configuration items specific to production environment
│   ├── config.test.js     # Configuration items specific to the test environment
│   ├── config.unittest.js # Configuration items specific to unit test environment
│   └── plugin.js          # Plug ins, which can be customized to enable or disable some plug-ins
├── jsconfig.json
├── note
│   ├── database.sql       # Create database script
│   ├── note.md            # Project Development Notes
│   └── tables.sql         # Create user table script
├── package.json
├── test                   # unit testing 
│   └── app
└── yarn.lock

Project configuration

If there is no database, execute the following sql to create a new database:

CREATE DATABASE IF NOT EXISTS template_node_egg DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;

Then import the user data table:

/*
 Navicat Premium Data Transfer

 Source Server         : local
 Source Server Type    : MySQL
 Source Server Version : 50722
 Source Host           : localhost:3306
 Source Schema         : template_node_egg

 Target Server Type    : MySQL
 Target Server Version : 50722
 File Encoding         : 65001

 Date: 02/01/2022 23:22:25
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `open_id` varchar(255) NOT NULL COMMENT 'Same as wechat openid',
  `union_id` varchar(255) DEFAULT NULL COMMENT 'Same as wechat unionid,As a reserved field, it does not necessarily have a value',
  `nick_name` varchar(255) NOT NULL COMMENT 'Nickname, same as wechat nickName',
  `password` varchar(255) DEFAULT NULL COMMENT 'The login password, as a reserved field, does not necessarily have a value',
  `avatar_url` text NOT NULL COMMENT 'Avatar, same as wechat avatarUrl',
  `phone` varchar(255) DEFAULT NULL COMMENT 'Mobile number, may be empty',
  `gender` int(11) DEFAULT NULL COMMENT 'Gender, may be empty',
  `country` varchar(255) DEFAULT NULL COMMENT 'Country, may be empty',
  `province` varchar(255) DEFAULT NULL COMMENT 'Province, may be empty',
  `city` varchar(255) DEFAULT NULL COMMENT 'City, may be empty',
  `language` varchar(255) DEFAULT NULL COMMENT 'Language, may be empty',
  `logged_at` datetime DEFAULT NULL COMMENT 'Last login time',
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of user
-- ----------------------------
BEGIN;
INSERT INTO `user` VALUES (1, 'o8FXk5E4u7hwaguN6kSq-KPXApJ1', NULL, 'Test account', NULL, 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20180520%2F0473e00bdfd2476fbe0c228a45a1652c.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1628131130&t=05ee794a54bad8edd2fd8bb2536db5b9', NULL, NULL, NULL, NULL, NULL, NULL, '2022-01-01 23:59:59', '2022-01-01 23:59:59', '2022-01-01 23:59:59');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

Then yarn dev starts the development. If it is started for the first time, it may need to be in config / config local. JS modify the password configuration:

config.sequelize = {
  // Connect users
  username: 'root',
  // Connection password
  password: '',
  // The connected database can be changed into the existing database as needed
  database: 'template_node_egg',
  // Connection address
  host: '127.0.0.1',
  // Database type
  dialect: 'mysql'
}

If the user table field in the existing database follows model / user The defined in JS is not correct and needs to be modified, otherwise an error will be reported

Application configuration

Customized application configuration, which takes effect globally after modification.

// Interface prefix name, which is modified with the business system
const apiPrefixName = 'api'
// Interface full prefix
const apiPrefix = `/${apiPrefixName}`
// The background interface prefix is modified with the business system
const manageApiPrefixName = 'manage'
// Background interface prefix
const manageApiPrefix = `/${manageApiPrefixName}`
const userConfig = {
  // The application name is used to specify the directory of log files and the key of cookie s. It is unique. The default is app Name, which can also be changed to other strings
  appName: app.name,
  apiPrefixName,
  apiPrefix,
  manageApiPrefixName,
  manageApiPrefix,
  // The default code and error message configuration only needs to be changed
  resCode: {
    // Successful code identification
    success: {
      code: 0
    },
    // Error code identification and prompt
    error: {
      code: 602, message: 'Parameter exception'
    },
    // code identification and prompt of server exception
    serverError: {
      code: 500, message: 'Server exception'
    },
    // Unregistered code ID and prompt
    notLogged: {
      code: 601, message: 'Please login before operation'
    }
  }
}

Cookie configuration

For example, the built-in interface and the background service interface in the scaffold are not required. The middle and background interface services are optional. If you don't want to put them together, you can ignore them directly.

The application interface service uses CTX session. [keyname] to set and obtain values. For example, if you want to set the id field as a cookie, the way to set a cookie is:

ctx.session.id = 1

To get a cookie is:

ctx.service.user.info(ctx.session.id)

CTX is required to obtain the interface service in the middle and background cookies. Get (key, cookie) method. See here for specific usage ctx. Cookie usage document.

Security policy configuration

  • Eggis enabled by default The security policy provided by JS.

  • By default, cross domain is allowed for scaffolds, but this setting is turned off in the production environment, and the white list is automatically added, which makes it easier to start development:

// Front end port, modified according to the actual situation
const port = 9001
const domainWhiteList = [
  ...new Set([
    `http://127.0.0.1:${port}`,
    `http://localhost:${port}`,
    // Attempt to automatically obtain the whitelist of local IP settings when the service is started
    `http://${getLocalhost()}:${port}`
  ])
]
config.security = {
  domainWhiteList
}
// Cross domain is allowed by default, and this setting is turned off in the production environment
config.cors = {
  origin: '*',
  allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'
}

Permission configuration

The interface services with login system basically need to specify some interfaces that can be accessed without login. The scaffold has built-in white list interfaces related to login:

[
  `${apiPrefix}/user/mock`,
  `${apiPrefix}/user/login`,
  `${apiPrefix}/user/logout`,
  `${apiPrefix}/user/phone`
]

Auto generate document configuration

Built in egg swagger doc plug-in, write interface notes according to the contract, and then automatically generate interface use documents. All data model structures are defined in app/contract.

See here for specific use documents Egg swagger doc usage document , I won't repeat it here.

If this function is not required, it can also be found in config / plugin Disable automatic document generation in JS:

{
  swaggerdoc: {
    enable: false,
    package: 'egg-swagger-doc'
  }
}

development

Generally, to develop a new interface, you need to complete the following four steps:

New model

Add a new log in app/model JS file and add data model:

'use strict'

/**
 * Log table
 */

module.exports = app => {
  // Sequelize. Data type provided by JS
  const { STRING } = app.Sequelize

  const Log = app.model.define(/* Data sheet name */ 'log', {
    // Data table fields
    content: {
      // Field type
      type: STRING(255),
      // field comment
      comment: 'Operation content'
    },
    remarks: {
      type: STRING(255),
      allowNull: false,
      comment: 'remarks'
    },
    actionType: {
      type: STRING(255),
      comment: 'Operation type'
    }
  })

  return Log
}

New services

Add a log in app/service JS file and add a database operation method to get the list:

'use strict'

const Service = require('egg').Service

class LogService extends Service {
  // Get log list
  async logs(actionType) {
    const { ctx } = this
    try {
      const data = await ctx.model.Log.findAll({
        where: {
          actionType
        }
      })
      return ctx.helper.clone(data)
    } catch (error) {
      ctx.logger.error(error)
    }
    return false
  }
}

module.exports = LogService

New controller

In APP / contract / dto JS to add a logInfo model:

{
  // ...

  logInfo: {
    content: { type: 'string', description: 'Operation content' },
    remarks: { type: 'string', description: 'remarks' },
    actionType: { type: 'string', description: 'Operation type' }
  }
}

Then add a new log in app/controller JS file and add a method to get the list:

'use strict'

const Controller = require('egg').Controller

/**
 * @controller Log Log module
 */
class LogController extends Controller {
  /**
   * @summary Get operation record list
   * @description Query the user action list according to the specified filter criteria
   * @router get /log/logs
   * @response 0 logInfo Log list
   */
  async logs() {
    const { ctx } = this
    const { actionType } = ctx.request.query

    // Parameter verification
    const rules = {
      actionType: { required: true, message: 'Operation type cannot be empty' }
    }
    const passed = await ctx.validate(rules, ctx.request.query)
    if (!passed) return

    const data = await ctx.service.log.logs(actionType)
    if (data) {
      this.ctx.helper.success(data)
    } else {
      this.ctx.helper.error(null, 'Log list failed')
    }
  }
}

module.exports = LogController

New interface

In APP / router JS adds a new routing interface:

// Get log list
subRouter.get('/log/logs', controller.log.logs)

The above steps are simple, of course.

Of course, when adding an interface, you don't need to add another controller file. Basically, you add a method to a controller, and then add a database operation method to the service.

release

Before publishing, it needs to be in config / config Configure the database connection configuration in prod.js:

config.sequelize = {
  username: 'root',
  password: '',
  database: 'template_node_egg',
  host: '127.0.0.1',
  dialect: 'mysql'
}

Start:

yarn start

stop it:

yarn stop

Using WY cli to create scaffolding

Global installation:

npm i @wytxer/wy-cli -g

Then execute the WY init project name command to install the scaffold, and select the background scaffold from the list:

❯ Backstage scaffold( Node.js + Egg.js + Sequelize)

Common commands of scaffold:

# install
yarn install

# Start development
yarn dev

# Production environment startup
yarn start

# Production environment stop
yarn stop

GitHub

Background scaffold GitHub address

Keywords: Javascript node.js Front-end

Added by clairian on Fri, 11 Feb 2022 06:23:01 +0200