Writing in the front

This article is suitable for the back-end development field is relatively strange to the primary front-end development partners, if you want to one person to complete a whole project (server-side interface definition development + front-end page rendering + database construction + server construction + deployment online), I hope this article can bring you a little reference value.

Project introduction

Realize simple login, add, delete, change and check forms, file upload and other functions. Server source code (PS: database RNpxDemo.sql in the home directory)

Technology stack

The front end

Mainly based on React family bucket, use Ant-Design-Pro UI framework. The front-end part does not do too much verbose, interested can directly view the source code.

The service side

Nodejs is used on the server side and Koa2.0 is used on the framework

Directory Structure description

├─ bin │ ├─ index.js# project entry file│ ├ ─ ─ the WWW# config import├─ config │ ├─ config.js# Config project│ ├ ─ ─ the js# database configuration│ ├ ─ ─ redis# redis configuration│ ├ ─ ─ render. JsData interface rendering├─ app │ ├─ ControllersThe operation layer performs server-side template rendering, json interface returns data, page jump│ │ ├ ─ ─ admin. Js │ │ ├ ─ ─ index. The js │ │ ├ ─ ─ the user. The js │ │ └ ─ ─ work. Js │ ├ ─ ─ middleware# Middleware collection│ ├─ ├─ ├─ exercisesThe data model layer performs data operations├─ ├─ exercises, exercises, exercisesThe routing layer controls routing│ │ ├ ─ ─ user. Js# /user/* Child routing│ │ ├ ─ ─ home. Js# Home page child route│ │ ├ ─ ─ index. Js# subroute summary file├ ─ ─ the static# static resources
Copy the code

The database

The database uses Mysql and the framework uses Sequelize, which is a Relational database Node.js ORM framework based on promise. It is quite convenient to use and recommended to use. Navicat Premium is a database management tool that you can use to install the mySql database

Cluster management

Cluster management adopts PM2, which is a Node application process manager with load balancing function. Pm2 is easy to install and useInstallation and use of PM2

API documentation tool

Here we share a library koA2-Swagger-UI that can automatically generate API documents. You can render JSON file API data into Swagger UI. For details, please refer to the project code.

npm i koa2-swagger-ui -D
Copy the code

Server configuration description

WWW entry file configuration

const koa = require("koa"); const koaSwagger = require('koa2-swagger-ui'); const router = require('.. /app/routers/index'); const path = require('path'); const koaBody = require('koa-body'); const { cross, onerror, onheader } = require(".. /app/middleware"); const pkg = require(".. /package.json"); const app = new koa(); app.use(onerror()); // System error, uniform error capture /* More configurations can be pulled to see the repository code */Copy the code

Database Configuration

The configuration file path is /config/db.js

Configure different database addresses for different environments:

const Sequelize = require('sequelize'); const { env } = require("./config"); let config = {}; Switch (env) {case "dev": config = {database: 'testDB', // 'dev@123', // password host: '127.0.01', // host name port: 3306 // port number, MySQL default 3306}; break; Case "test": config = {database: 'testDB', // Which database is used username: 'root', // username: 'test@123', // host: 'test.mysql.rds.aliyuncs.com', / / host name port: 3306 / / port, MySQL default 3306}; break; Case "PRD ": config = {database: 'testDB', // Which database is used username: 'root', // username: 'prd@123', // host: 'prd.mysql.rds.aliyuncs.com', / / host name port: 3306 / / port, MySQL default 3306}; break; } export const sequelize = new Sequelize(config.database, config.username, config.password, { host: config.host, dialect: 'mysql', pool: { max: 5, min: 0, idle: 30000 } });Copy the code

The routing configuration

The configuration file path is /app/routers/index.js

const router = new require('koa-router')() const home = require('./home') const user = require("./backend/user") const swaggerJSDoc = require('swagger-jsdoc') const pkg = require(".. /.. /package.json") const swaggerDefinition = {info: {title: 'API', version: '1.0.0', description: 'API',}, host: `localhost:${pkg.port}`, basePath: '/' // Base path (optional) }; const options = { swaggerDefinition, apis: ['. / app/routers/backend / *. Js', '. / app/routers/front / *. Js'], / / write annotated the storage address of the router}; Const swaggerSpec = swaggerJSDoc(options) router.get('/swagger.json', async function (ctx) { ctx.set('Content-Type', 'application/json'); ctx.body = swaggerSpec; }) router.use('', home.routes()) router.use('/backend/user', user.routes()) module.exports = routerCopy the code

Middleware collection

In layman’s terms: middleware is a series of operations done before or after routing matching.

const { renderData } = require(".. /.. /config/render") const { log } = require(".. /.. /util/utils") const koajwt = require('koa-jwt') /** * @example app.use(cross()) */ export function cross() { return async function (ctx, next) { ctx.set('Access-Control-Allow-Origin', ctx.get("Origin") == null ? "*" : ctx.get("Origin")); ctx.set('Access-Control-Allow-Methods', ctx.get("Access-Control-Request-Method") || "PUT, GET, POST, DELETE, OPTIONS"); ctx.set('Access-Control-Allow-Headers', ctx.get("Access-Control-Request-Headers") || "Content-Type"); ctx.set('Access-Control-Allow-Credentials', "true"); if (ctx.method == "OPTIONS") { ctx.status = 204 } await next(); }} /** * compatible route suffix, Json == XXX/XXX address * @param suffixes String [] suffix list * @example app.use(adaptRouteSuffix([".json"])) */ export function adaptRouteSuffix(suffixes = []) { return async function (ctx, next) { suffixes.forEach(e => { var re = new RegExp(e); ctx.path = ctx.path.replace(re, "") }) await next(); }} /** ** @example app.use(onError ()) */ export function onerror() {return async function (CTX, next) { return next().catch((err) => { if (err.status === 401) { ctx.status = 200; RenderData (CTX, NULL, 401, "user has no permissions ", err.message) } else if (ctx.status === 404) { var err = new Error('Not Found'); err.status = 404; RenderData (CTX, NULL, 404, "System busy, please contact administrator ", err.message); } else {renderData(CTX, null, -1, "server error ", err.message); log(err.message); }} /** * delay * @await delay(5000) // delay 5s */ export function delay(time) {return new Promise(function) (resolve) { setTimeout(function () { resolve(); }, time); }); }; /** * export function onheader() {return koajwt({secret: 'polo_token'}).unless({path: [/\/user\/login|swagger|front/] }) }Copy the code

Basic Function Display

The login

The login module, here is the introduction of the implementation of the server side, mainly depends on two plug-ins, JSONWebToken (JWT) and KOA-JWT. The former is mainly responsible for encryption, generating the token and returning it to the front end, while the latter realizes the verification of the token, realizes the request header interception in the middleware, and returns 401 if the verification fails. Specific code can refer to. / app/controllers/user. Js.

/** * user login * @return User login object */ export async function login(CTX) {const data = ctx.request.body; if (! data.name || ! Data.password) {renderData(CTX, null, 102, 'invalid '); } const result = await GetUser({ name: data.userName, password: data.password }) if (result ! == null) { const token = jwt.sign({ name: result.name, password: result.password }, 'polo_token', { expiresIn: '2h' }); Const userData = {userName: result.name, token: 'Bearer '+ token} renderData(CTX, userData, 0,' login successful '); } else {renderData(CTX, null, 101, 'wrong username or password '); }} /** * export function onheader() {return koajwt({secret: 'polo_token'}).unless({path: [/\/user\/login|swagger|front/] }) }Copy the code

Part of background content display

Write in the last

The above article is a brief version of my earlier full stack development project which has been online to share. At the beginning of the article, I have attached the source code of the project before and after, and provided the test data (RNpxDemo.sql). Just clone the code and ensure that the required software has been installed on the computer.