Build from scratch Node.js Enterprise web server (3): Middleware

Time:2021-3-1

About Middleware

In a broad sense, middleware refers to software that can provide functions for applications outside the operating system, ranging from various services of cloud computing vendors to detection modules of a certain field. Express middleware refers to the software module that provides functions based on express middleware mechanism. Express depends on 3. X and earlier versionsConnectAs the underlying middleware mechanism, the middleware mechanism compatible with connect has been built in since version 4. X, so the middleware based on connect can be directly used in express.

Express will organize the process in the form of queue, and call the process in turn by recursively passing the next method when dispatching the request (seeSource code):

Build from scratch Node.js  Enterprise web server (3): Middleware

Write a routing modification Middleware

Projects completed in the previous chapterhost1-tech/nodejs-server-examples – 02-validateThere is a small problem, unable to access the interface with non-standard path, such as unable to accesshttp://localhost:9000/api//shop

Build from scratch Node.js  Enterprise web server (3): Middleware

Now we use middleware to solve this problem

$MKDIR Src / middlewares # create a new Src / middlewares directory to store custom middleware

$ tree -L 2 -I node_ Modules # display except node_ Directory content structure outside modules
.
├── Dockerfile
├── package.json
├── public
│   ├── glue.js
│   ├── index.css
│   ├── index.html
│   └── index.js
├── src
│   ├── controllers
│   ├── middlewares
│   ├── moulds
│   ├── server.js
│   └── services
└── yarn.lock
// src/middlewares/urlnormalize.js
const { normalize } = require('path');
const { parse, format } = require('url');

module.exports = function urlnormalizeMiddleware() {
  return (req, res, next) => {
    //To solve the problem of inconsistent use of normalize path separator in windows and Linux systems
    const pathname = normalize(req.path).split('\\').join('/');
    const urlParsed = parse(req.url);

    let shouldRedirect = false;

    //Redirecting nonstandard paths
    if (req.path != pathname) {
      urlParsed.pathname = pathname;
      shouldRedirect = true;
    }

    //Perform redirection or skip
    if (shouldRedirect) {
      res.redirect(format(urlParsed));
    } else {
      next();
    }
  };
};
// src/middlewares/index.js
const { Router } = require('express');
const urlnormalizeMiddleware = require('./urlnormalize');

module.exports = async function initMiddlewares() {
  const router = Router();
  router.use(urlnormalizeMiddleware());
  return router;
};
// src/server.js
const express = require('express');
const { resolve } = require('path');
const { promisify } = require('util');
+const initMiddlewares = require('./middlewares');
const initControllers = require('./controllers');

// ...

async function bootstrap() {
  server.use(express.static(publicDir));
  server.use('/moulds', express.static(mouldsDir));
+  server.use(await initMiddlewares());
  server.use(await initControllers());
  await promisify(server.listen.bind(server, port))();
  console.log(`> Started on port ${port}`);
}

bootstrap();

visithttp://localhost:9000/api//shopYou can see the automatic redirection to a valid route:

Build from scratch Node.js  Enterprise web server (3): Middleware

Add logic to store

So far, the store management lacks the logic of store adding, because post parsing needs to rely onbody-parserThis is the middleware, so this function is added in this chapter. Execute the body parser installation command:

$ yarn add body-parser
# ...
info Direct dependencies
└─ [email protected]
# ...

Back end processing:

// src/services/shop.js
// ...
class ShopService {
  // ...
+  async create({ values }) {
+    await delay();
+
+    const id = String(
+      1 +
+        Object.keys(memoryStorage).reduce((m, id) => Math.max(m, id), -Infinity)
+    );
+
+    return { id, ...(memoryStorage[id] = values) };
+  }
}
// ...
// src/controllers/shop.js
const { Router } = require('express');
+const bodyParser = require('body-parser');
const shopService = require('../services/shop');
const { createShopFormSchema } = require('../moulds/ShopForm');

class ShopController {
  shopService;

  async init() {
    this.shopService = await shopService();

    const router = Router();
    router.get('/', this.getAll);
    router.get('/:shopId', this.getOne);
    router.put('/:shopId', this.put);
    router.delete('/:shopId', this.delete);
+    router.post('/', bodyParser.urlencoded({ extended: false }), this.post);
    return router;
  }

  // ...

+  post = async (req, res) => {
+    const { name } = req.body;
+
+    try {
+      await createShopFormSchema().validate({ name });
+    } catch (e) {
+      res.status(400).send({ success: false, message: e.message });
+      return;
+    }
+
+    const shopInfo = await this.shopService.create({ values: { name } });
+
+    res.send({ success: true, data: shopInfo });
+  };
}
// ...

Front end processing:

// public/index.js
// ...
export async function refreshShopList() {
  const res = await fetch('/api/shop');
  const { data: shopList } = await res.json();
  const htmlItems = shopList.map(
    ({ id, name }) => `
<li data-shop-id="${id}">
  <div data-type="text">${name}</div>
  < input type = "text" placeholder = "enter new store name" / >
  To confirm the modification</a>
  To delete a store</a>
  <div class="error"></div>
</li>`
  );
  document.querySelector('#root').innerHTML = `
<h1>Shop list:</h1>
-<ul class="shop-list">${htmlItems.join('')}</ul>`;
+<ul class="shop-list">${htmlItems.join('')}</ul>
+< H1 > new stores:</h1>
+<form method="post" action="/api/shop">
+< label > name of new store: < / label >
+  <input type="text" name="name" />
+< button type = submit "data type = create > confirm new < / button > Add
+  <span class="error"></span>
+</form>`;
}

export async function bindShopInfoEvents() {
  document.querySelector('#root').addEventListener('click', async (e) => {
    e.preventDefault();
    switch (e.target.dataset.type) {
      case 'modify':
        await modifyShopInfo(e);
        break;
      case 'remove':
        await removeShopInfo(e);
        break;
+      case 'create':
+        await createShopInfo(e);
+        break;
    }
  });
}

// ...

+export async function createShopInfo(e) {
+  e.preventDefault();
+  const name = e.target.parentElement.querySelector('input[name=name]').value;
+
+  try {
+    await createShopFormSchema().validate({ name });
+  } catch ({ message }) {
+    e.target.parentElement.querySelector('.error').innerHTML = message;
+    return;
+  }
+
+  await fetch('/api/shop', {
+    method: 'POST',
+    headers: {
+      'Content-Type': 'application/x-www-form-urlencoded',
+    },
+    body: `name=${encodeURIComponent(name)}`,
+  });
+
+  await refreshShopList();
+}

Take a look at the effect of new stores:

Build from scratch Node.js  Enterprise web server (3): Middleware

Source code of this chapter

host1-tech/nodejs-server-examples – 03-middleware

Read more

Build from scratch Node.js Enterprise web server (zero): static services
Build from scratch Node.js Enterprise web server (1): interface and layering
Build from scratch Node.js Enterprise web server (2): Verification
Build from scratch Node.js Enterprise web server (3): Middleware
Build from scratch Node.js Enterprise web server (4): exception handling
Build from scratch Node.js Enterprise web server (5): database access
Build from scratch Node.js Enterprise web server (6): session
Build from scratch Node.js Enterprise web server (7): authentication login
Build from scratch Node.js Enterprise web server (8): network security
Build from scratch Node.js Enterprise web server (9): configuration items
Build from scratch Node.js Enterprise web server (x): log
Build from scratch Node.js Enterprise web server (11): timed tasks
Build from scratch Node.js Enterprise web server (12): remote call
Build from scratch Node.js Enterprise web server (XIII): breakpoint debugging and performance analysis
Build from scratch Node.js Enterprise web server (14): automated testing
Build from scratch Node.js Enterprise web server (XV): summary and Prospect

Recommended Today

Programming Xiaobai must understand the network principle

How is the network composed? Why can we easily surf the Internet now?Whether you are a computer major or not, you may always have such questions in your heart!And today we will solve this matter and tell you the real answer! Basic composition of network First, let’s look at this sentence Connect all computers together […]