Recently, I was writing a custom interface for a project. For the first time, I used node.js to implement it. I searched books and materials for several days. I planned to use express + mongodb to implement it. Later, I found that Koa, good boy, mysql is the final choice of the database. Old fashion, I built a framework based on Koa + Mysql:
Koa
Koa is a small, expressive and robust Web framework built by Express's original team. By compiling web applications with koa and combining different generator s, the redundant nesting of callback functions can be avoided, and the efficiency of error handling can be greatly improved. Koa does not bind any Middleware in the kernel method. It only provides a lightweight and elegant Library of functions, which makes it easy to write Web applications.
General framework
The project is mainly divided into config and app:
config: Configuration file
app: Following the MVC architecture, application files
Third party package
sequelize is the ORM framework under node. It is very good and powerful. It will be shown in the following examples.
Main configuration
Server.js
/** * Created by vslimit on 2017/9/8. */ 'use strict'; require('dotenv').config(); const Koa =require('koa'); const app = new Koa(); const fs = require('fs'); const join = require('path').join; const bodyParser = require('koa-bodyparser'); const model = join(__dirname, 'app/model'); var Router = require('koa-router'); var router = new Router(); const rest = require('./config/rest'); const config = require('./config'); const port = process.env.PORT || 3000; module.exports = app; app.use(bodyParser()); // app.use(async ctx => { // ctx.body = ctx.request.body; // }); app.use(rest.restify()); app.use(router.routes()).use(router.allowedMethods()); fs.readdirSync(model) .filter(file => ~file.search(/^[^\.].*\.js$/)) .forEach(file => require(join(model, file))); // let files = fs.readdirSync(model); require('./config/routes')(router); listen(); module.exports = model; function listen() { if (router.get('env') === 'test') return; app.listen(port); console.log('Express app started on port ' + port); }
Development example
We use this framework to develop a Restful interface for function registration, login and loading. Let's look at the model first.
User
/** * Created by vslimit on 2017/9/10. */ const db = require('../util/db'); const crypto = require('crypto'); const uuid = require('node-uuid'); const User = db.defineModel('users', { name: { type: db.STRING(), allowNull: true }, email: { type: db.STRING(), unique: true, allowNull: true }, password: db.VIRTUAL(), mobile: { type: db.STRING(), unique: true }, provider: db.STRING(), hashed_password: db.STRING(), salt: db.STRING(), auth_token: { type: db.STRING(), allowNull: true }, access_token: { type: db.STRING(), allowNull: true } }); User.beforeValidate(function (user) { if (user.isNewRecord) { let salt = this.methods.makeSalt(); user.set('salt', salt); user.set('hashed_password', this.methods.encryptPassword(user.password, salt)); } }); User.afterCreate(function (user) { console.log(JSON.stringify(user)); user.access_token = this.methods.makeAccessToken(user.id); console.log(user.access_token); user.save(); }); User.methods = { authenticate: function (password, salt, hashed_password) { return this.encryptPassword(password, salt) === hashed_password; }, /** * Make salt * * @return {String} * @api public */ makeSalt: function () { return Math.round((new Date().valueOf() * Math.random())) + ''; }, /** * Encrypt password * * @param {String} password * @return {String} * @api public */ encryptPassword: function (password, salt) { if (!password) return ''; try { return crypto .createHmac('sha1', salt) .update(password) .digest('hex'); } catch (err) { return ''; } }, makeAccessToken: function (id) { return crypto .createHmac('sha1', id.toString()) .update(uuid.v4() + Date.now()) .digest('hex'); }, load: function (condition) { return User.findOne({where: condition}); }, count: function (condition) { return User.count({where: condition}); }, }; module.exports = User;
Then controller
users
/** * Created by vslimit on 2017/9/12. */ 'use strict'; const User = require('../model/User'); const ApiResult = require('../../config/rest').APIResult; /** * Create user */ exports.create = async(ctx, next) => { let mobile = ctx.request.body.mobile; let password = ctx.request.body.password; console.log(mobile); console.log(password); if (!mobile || !password) { ctx.rest(ApiResult("", -102, "Mobile number or password cannot be empty")); } else { let count = await User.methods.count({mobile: mobile}); console.log(count); if (count > 0) { ctx.rest(ApiResult("", -101, "Mobile number already exists")); } else { let user = await User.create({ mobile: mobile, password: password, provider: 'local' }); ctx.rest(ApiResult(user.access_token)); } } }; exports.login = async(ctx, next) => { let mobile = ctx.request.body.mobile; let password = ctx.request.body.password; if (!mobile || !password) { ctx.rest(ApiResult("", -102, "Mobile number or password cannot be empty")); } else { let user = await User.methods.load({mobile: mobile}); if (user) { if (User.methods.authenticate(password, user.salt, user.hashed_password)) { ctx.rest(ApiResult({ name: user.name, mobile: user.mobile, access_token: user.access_token })); } else { ctx.rest(ApiResult("", -105, "User password error")); } } else { ctx.rest(ApiResult("", -103, "user does not exist")); } } }; exports.load = async(ctx, next) => { var u = await User.findById(ctx.params.id); ctx.rest(ApiResult(u)); };
Configure route
app.post('/api/users', users.create); app.post('/api/login', users.login); app.get('/api/users/:id', users.load);
Function
So far, the framework of Web Server based on Koa and Mysql has been built, and the functions of registration, login and loading user's personal information have been realized.
Reference material
The main reference in the project
General framework
sequelize document
Part of the code comes from Liao Xuefeng's official website
Official website
git
Code
All the code in this article has been submitted to git. If you like, go to star t under git.
Koa-Server's code is detailed in:[ https://github.com/vslimit/koa-server.git)