preface
This article was written while I was building the Node server infrastructure and is the first in this series, with more updates on some of the ideas I implemented on the project. Follow the author into the koA2 project construction!
Environment to prepare
I. Project initialization
// 1. Ensure that Node.js is installed
node -v
// 2. Ensure that NPM or YARN has been installedNPM -v or yarn-v// 3. Enter the empty project file koa2(project name)
cd koa2
// 4. Initialize package.json
yarn init
Install koA
yarn add koa -s
Copy the code
Second, test the minimum system
- The new app. Js
const Koa = require("koa"); const app = new Koa(); app.use(async (ctx) => { ctx.body = "hello koa2"; }); app.listen(3000); Console. log(" server on: http://localhost:3000/");Copy the code
- Operating system
node app.js
Copy the code
- Viewer open
http://localhost:3000/
Copy the code
After the above minimum system test, we can check whether there is a problem with our project initialization, but we will reduce the errors in the following work.
Three, install middleware
- Koa-onerror Indicates an error message
- Koa-bodyparser parses json request data in the body
- Koa – logger logs
- Koa – cors across domains
- Koa -static Indicates static resources
- Koa – the router routing
- Nodemon hot update
- The debug debug mode
yarn add koa-router koa-onerror koa-bodyparser koa-logger koa-cors koa-static nodemon debug --save
Copy the code
Install the database
- Because the author is familiar with mysql, the database uses mysql
yarn add mysql --save
Copy the code
5. Final directory structure
- Middelware middleware
- Controller, service code of the control layer
- Config Database Settings
- Dbhelper SQL statements
- Routes routing
- Modal object layer
│ app. Js │ package. Json │ REAAME. Md │ yarn. The lock ├ ─ app │ ├ ─ controller │ │ users. Js │ │ │ └ ─ modal │ users. Js ├ ─ bin │ WWW ├ ─ config │ constant. Js │ database. Js │ dbPool. Js ├ ─ dbhelper │ users. Js ├ ─ middlewares │ │ index. The js │ └ ─ middleware │ ├─ ├─ ├─ garbage ├─public │ faviconCopy the code
Basic configuration
1. Rewrite app.js
- Registered middleware
const Koa = require("koa");
const app = new Koa();
const onerror = require("koa-onerror");
const bodyparser = require("koa-bodyparser");
const logger = require("koa-logger");
const router = require("./routes/index");
const cors = require("koa-cors");
/ / registration error
onerror(app);
/ / register bodyparser
app.use(bodyparser());
// Register logs
app.use(logger());
// Register static resources
app.use(require("koa-static")(__dirname + "/public"));
// Register across domains
app.use(cors());
// Register custom middleware
require('./middlewares/index')(app);
// Register the route
app.use(router.routes(), router.allowedMethods());
// logger-handling
app.use(async (ctx, next) => {
const start = new Date(a);await next();
const ms = new Date() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
// error-handling
app.on("error".(err, ctx) = > {
console.error("server error", err, ctx);
});
module.exports = app;
Copy the code
- Koa-onerror, KOA-BodyParser, KOA-Logger, KOA-CORS and other middleware are common MIDDLEWARE of KOA, and the usage will not be introduced here
- Koa-router and Middlewares do some custom operations, which are described below
2. Add project entry
- Create the entry file bin/ WWW
#! /usr/bin/env node
/** * Module dependencies. */
var app = require('.. /app');
var debug = require('debug') ('demo:server');
var http = require('http');
/** * Get port from environment and store in Express. */
var port = normalizePort('3000');
// app.set('port', port);
/** * Create HTTP server. */
var server = http.createServer(app.callback());
/** * Listen on provided port, on all network interfaces. */
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/** * Normalize a port into a number, string, or false. */
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/** * Event listener for HTTP server "error" event. */
function onError(error) {
if(error.syscall ! = ='listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
// process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
// process.exit(1);
break;
default:
throwerror; }}/** * Event listener for HTTP server "listening" event. */
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
Copy the code
Rewrite package.json
- Adding a Startup Script
"scripts": {
"start": "node bin/www"."dev": "nodemon bin/www" / / hot update
},
Copy the code
- The complete package. Json
// package.json
{
"name": "koa2"."version": "1.0.0"."description": "koa2+mysql"."main": "index.js"."license": "MIT"."scripts": {
"start": "node bin/www"."dev": "nodemon bin/www"
},
"dependencies": {
"debug": "^ 4.3.3." "."koa": "^ 2.13.4." "."koa-bodyparser": "^ 4.3.0"."koa-cors": "^ 0.0.16"."koa-logger": "^ 3.2.1." "."koa-onerror": "^ 4.1.0." "."koa-router": "^ 10.1.1"."koa-static": "^ 5.0.0"."mysql": "^ 2.18.1"."nodemon": "^ 2.0.15"}}Copy the code
Add static pages
- When we register static resources in app.js, we know that we put them in the public folder
- Create the index.html page
<! DOCTYPE html> <html lang="en"> ... </html>Copy the code
- Add the favicon.ico icon
5. Start the project
- Start the project
// yarn dev Specifies hot update yarn devCopy the code
- Viewer open
http://localhost:3000/
Copy the code
- With koA-static static resource processing, the root directory is opened by default
/public/index.html
. - Access does not require adding public, i.e
The file name http://localhost:3000/
This form is accessible.
The routing configuration
- Routes are split into modules to facilitate route decoupling.
- The registered routes are decoupled from the business layer to facilitate the reuse of business logic.
- Add route prefixes in the routing module to make routes easier to read.
- Those of you who have used Webpack will know that you can get a qualified context by using require.context.
One, the implementation of automatic file loading function
- Create the file utils/ autoloadfile.js
#! /usr/bin/env node
const path = require("path");
const fs = require("fs");
const getPathInfo = (p) = > path.parse(p);
/ * * *@description // Recursively read the file, similar to webpack's require.context() *@param {String} Directory File directory *@param {Boolean} UseSubdirectories Whether to query subdirectories. Default: false *@param {array} ExtList query file suffix, default ['.js'] */
const autoLoadFile = (
directory,
useSubdirectories = false,
extList = [".js"]
) = > {
const filesList = [];
// Read files recursively
function readFileList(directory, useSubdirectories, extList) {
const files = fs.readdirSync(directory);
files.forEach((item) = > {
const fullPath = path.join(directory, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory() && useSubdirectories) {
readFileList(path.join(directory, item), useSubdirectories, extList);
} else {
constinfo = getPathInfo(fullPath); extList.includes(info.ext) && filesList.push(fullPath); }}); } readFileList(directory, useSubdirectories, extList);// Generate the required objects
const res = filesList.map((item) = > ({
path: item,
data: require(item), ... getPathInfo(item), }));return res;
};
module.exports = autoLoadFile;
Copy the code
- Use the sample
const context = require(".. /utils/autoLoadFile");
const fileList = context(path.join(__dirname, "./route"), true);
Copy the code
2. Route self-registration
- Create the routes/index.js self-executing file
const router = require("koa-router") ();const path = require("path");
const context = require(".. /utils/autoLoadFile");
/ * * *@param {Array} List of files that arR needs to register routes */
function importAll(arr) {
arr.forEach((key) = > {
// This method is used by nested routines
router.use("/api", key.data.routes(), key.data.allowedMethods());
});
}
importAll(context(path.join(__dirname, "./route"), false));
module.exports = router;
Copy the code
3. Register routes
- app.js
// routes/index) const router = require("./routes/index"); App.use (router.routes(), router.allowedmethods ());Copy the code
4. Create a routing module
- Now that the infrastructure is ready, try creating a module
// routes/route/users.js const router = require("koa-router")(); // Module route prefix router.prefix("/users"); router.post("/", function (ctx, next) { ctx.body = "this a users response!" ; }); /** * @param {username} username * @param {password} password */ router.post("/login", async (ctx) => { const request = ctx.request.body; const { username, password } = request; If (the username & password) {CTX. Body = {" code ": 200," MSG ":" success ", "data", "login succeeds"}}}); module.exports = router;Copy the code
-
The final routing path: localhost: 3000 / API/users/login
/api
Is the route prefix./users
Is the module route prefix/login
Specific interface
-
The results of
Middleware configuration
1. Middleware self-registration
- Creates a self-executing file middlewares/index.js
const path = require("path"); const context = require(".. /utils/autoLoadFile"); /** * @param {Array} arr */ const install = (app) => {context(path.join(__dirname, ". false).forEach((key) => { app.use(key.data); }); }; module.exports = install;Copy the code
Second, middleware registration
- app.js
// Register custom middleware
require('./middlewares/index')(app);
Copy the code
Response body middleware
- Create message.js middleware that encapsulates the response body
// middlewares/middleware/message.js
module.exports = async (ctx, next) => {
ctx.res.$success = (data, code = 200) = > {
const _data = {
code,
};
if (typeof data === "object") {
_data.msg = "success";
_data.data = data;
} else {
_data.msg = data;
}
ctx.body = _data;
};
ctx.res.$error = (err, code = 500) = > {
const _data = {
code,
};
if (typeof err === "object") {
_data.msg = "error";
_data.data = JSON.stringify(err);
} else {
_data.msg = err;
}
ctx.body = _data;
};
await next();
};
Copy the code
Examples of response body middleware
router.post('/login'.async (ctx) => {
const request = ctx.request.body;
const { username, password } = request;
if (username&&password) {
ctx.res.$success('Login successful');
} else {
ctx.res.$error("Request failed".403); }})Copy the code
5. Response body middleware results
Success / / {" code ": 200," MSG ":" success ", "data", "login succeeds"} failure / / {" code ": 403," MSG ":" error ", "data" : "request failed}"Copy the code
The resources
- Koa website koajs.com/
- Koa middleware use of Koa – the router www.jianshu.com/p/f169c342b…
- Koa – the router official documentation wohugb. Gitbooks. IO/koajs/conte…
- Koa – github.com/koajs/bodyp bodyparser source code…
- Koa – error source github.com/koajs/error…
- Koa – github.com/koajs/logge logger source code…
conclusion
In this paper, a relatively simple project architecture is built from the point of view of project initialization, and automatic registration of routing and middleware is realized.
I will continue to update this article from the perspectives of building RESTFUL apis, login token verification, permission management, and more.
I am Front-end Creek. If you are interested, please follow the official account of Front-end Creek and add me on wechat wXL-15153496335.
Gitee warehouse address for a star thank you!!