koa builds nodejs project and registers interfaces

The logic processing of registering interfaces with nodejs will be complicated. The development process can be simplified directly through express or KOA. It is recorded here that using koa to build nodejs projects and register interfaces. If you are not familiar with koa, you can refer to this article. Make it easier for nodejs to start the service – koa chapter

Project structure

The overall structure of the project is as follows. The files with different functions are divided into modules to make the code logic clearer

node_modules      // Installed packages
src                     // Own coding part
    app               // Registered app
    constants        // Define constants
    controller       // The method used to register the interface
    middleware     // Middleware for processing data
    router            // route
    service            // Define sql statements
    utils               // Method of processing data
    main.js           // entrance
.env                    // Put the configuration file of the environment variable 
package-lock.json  // Package dependencies
package.json        // Which packages need to be installed

Register app

All operations in koa need to be completed through the registered app object. First register and export in app/index.js

const Koa = require('koa')
const app = new Koa()
    
module.exports = app

http open service

Create the main.js file in the project root directory, introduce the app object, and start the http service

const app = require('./app')
const { APP_PORT } = require('./app/config')
app.listen(APP_PORT, ()=>{
    console.log('Open the service')
})

It is not safe to write the account, password, port number and other information directly in the file. It is easy to leak when uploading or sharing the project, so save it to the file that does not affect the project. Add an. env file in the root directory, and use dotenv to register the configuration items in the. env file into the environment variable

APP_PORT=8000

A new config.js file is added in the app folder to save configuration information and prevent arbitrary changes

const dotenv = require('dotenv')
dotenv.config();

module.exports = {
    APP_PORT
} = process.env

Start main.js to listen to port 8000. Since there is no response to the request, you can only return Not Find when accessing 8000

Register routing

A group of routes is a group of mapping relationships, defining paths and processing functions. The following demonstrates the registered interface logic. The middleware is used to judge the correctness of data, and the functions of the control layer are used to respond

const Router = require('koa-router')
const RegisterRouter = new Router({ prefix: '/register' })
const { register } = require('../controller/register.controller')
const { verifyUser, encryptionPwd } = require('../middleware/register.middleware')

RegisterRouter.post('/', verifyUser, encryptionPwd, register)
module.exports = RegisterRouter

middleware

Judge whether the user name and password have been passed in and whether they have been registered, and encrypt the incoming private data

const crypto = require('crypto')
const { hasUser } = require('../service/register.service')
const { USER_ALREADY_EXISTS,
  NAME_OR_PASSWORD_REQUIRED } = require('../constants/error-types')
  
class RegisterMiddleWare {
  async verifyUser(ctx, next) {
    const { name, password } = ctx.request.body
    if (!name || !password) {
      const error = new Error(NAME_OR_PASSWORD_REQUIRED)
      return ctx.app.emit('error', error, ctx)
    }
    let users = await hasUser(name)
    if (users) {
      const error = new Error(USER_ALREADY_EXISTS)
      return ctx.app.emit('error', error, ctx)
    }
    await next()
  }
  
  async encryptionPwd(ctx, next) {
    const { password } = ctx.request.body
    const md5 = crypto.createHash('md5')
    const pwd = md5.update(password).digest('hex')
    ctx.request.body.password = pwd
    await next()
  }
}

module.exports = new RegisterMiddleWare()

Establish connection with database

Create table structure

CREATE TABLE IF NOT EXISTS `user`(
    id INT PRIMARY KEY AUTO_INCREMENT,
    name varchar(50) NOT NULL UNIQUE,
    password varchar(200) NOT NULL,
    createAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updateAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

The method of inserting the database is defined in service/register.service.js

const connection = require('../app/database')
class RegisterService {

  async hasUser(name) {
    const statement = `SELECT * FROM user WHERE name = ?`
    try {
      const [result] = await connection.execute(statement, [name])
      return result.length
    } catch (error) {
      console.log('LoginService-hasUser', error)
    }
  }
  
  async insertUser(name, password) {
    const statement = `INSERT INTO user(name, password) VALUES(?,?)`
    try {
      const [result] = await connection.execute(statement, [name, password])
      return result
    } catch (error) {
      console.log('LoginService-insertUser', error)
    }
  }
}

module.exports = new RegisterService()

Many places need to connect to the database, so a unified connection pool is established in app/databse.js

const mysql = require('mysql2')
const { MYSQL_HOST,
  MYSQL_PORT,
  MYSQL_DATABASE,
  MYSQL_USER,
  MYSQL_PASSWORD, } = require('./config')
const connection = mysql.createPool({
  database: MYSQL_DATABASE,
  host: MYSQL_HOST,
  port: MYSQL_PORT,
  user: MYSQL_USER,
  password: MYSQL_PASSWORD
})
connection.getConnection((error, conn)=>{
  conn.connect((err)=>{
    console.log(error, err)
  })
})
module.exports = connection.promise()

There will be problems when the database account and password are directly hard coded in the code. Similarly, they are written to the. env file and exported through config.js

// .env
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_DATABASE=mall
MYSQL_USER=root
MYSQL_PASSWORD=123456
APP_PORT=8000
// config.js
const dotenv = require('dotenv')
dotenv.config()
module.exports = {
  APP_PORT,
  MYSQL_HOST,
  MYSQL_PORT,
  MYSQL_DATABASE,
  MYSQL_USER,
  MYSQL_PASSWORD,
} = process.env

Capture error

When registering an account, the user has registered or the password does not meet the specification. You need to return an error message. Define common error messages in constants / error types

const USER_ALREADY_EXISTS = 'user_already_exists'
const NAME_OR_PASSWORD_REQUIRED = 'name_or_password_required'
module.exports = {
  USER_ALREADY_EXISTS,
  NAME_OR_PASSWORD_REQUIRED
}

Judge the error information in app/error-handle.js

const {
  USER_ALREADY_EXISTS
} = require('../constants/error-types')
const errorHandle = (error, ctx) => {
  let code = 200
  let message = ''
  switch (error.message) {
    case USER_ALREADY_EXISTS:
      message = 'The user already exists'
      break;
  }
  ctx.status = code
  ctx.body = message
}
module.exports = errorHandle

app/index.js introduces the interface defined by the route, obtains the parameters passed by the post request, and binds the error handling method

const Koa = require('koa')
const app = new Koa()
const bodyParser = require('koa-bodyparser')
const LoginRouter = require('../router/register.router')
const errorHandle = require('./error-handle')
app.use(bodyParser())
app.use(LoginRouter.routes())
app.use(LoginRouter.allowedMethods())
app.on('error', errorHandle)
module.exports = app

Respond

Define the corresponding processing method in controller/register.controller.js

const { insertUser } = require('../service/register.service')
class RegisterController {
  async register(ctx, next) {
    const { name, password } = ctx.request.body
    const result = await insertUser(name, password)
    ctx.body = result
  }
}
module.exports = new RegisterController()

So far, we can access the interface

The above is the complete process of registering an interface. Different interfaces may need to be processed through different middleware. For example, the login interface needs to verify the password and distribute the token, and other interfaces related to user rights need to verify the token.

Here are some related notes for reference
jwt implements token authentication (nodejs koa)
How to authenticate through cookie and session (nodejs/koa)
Super detailed mysql summary (DQL)
Super detailed mysql summary (basic concepts, DDL, DML)
How to create a service using http in nodejs

Tags: node.js

Posted on Sun, 19 Sep 2021 22:59:59 -0400 by mithril