Flexible use of middleware mechanism can effectively extend the functions of the architecture. The main effects of middleware are interception and restructuring

  1. interception: For example, judging user privileges through middleware and suspending subsequent execution if no privileges exist
  2. restructuring: For example, the data sent from the frontend is validated by middleware and transformed into the desired type

Here, through a virtual requirement, we use middleware to achieve the effects of interception and restructuring:

  1. Requirement: The frontend sends two parameters: a and b, and the backend calculates the sum of them and returns them to the frontend
  2. interception: The middleware judges whether the parameters are undefined. If they are undefined, subsequent execution will be aborted
  3. restructuring: Cast parameters type to Integer

Create Middleware

1. Declaration of Middleware

src/suite-vendor/test-party/modules/test-party/backend/src/config/config.js

  1. 1// middlewares
  2. 2config.middlewares = {
  3. 3 testInterception: {
  4. 4 bean: 'testInterception',
  5. 5 global: false,
  6. 6 dependencies: 'instance',
  7. 7 },
  8. 8 testRestructuring: {
  9. 9 bean: 'testRestructuring',
  10. 10 global: false,
  11. 11 dependencies: 'instance',
  12. 12 },
  13. 13};
名称 说明
bean The bean component name used to implement middleware logic
global Whether global middleware or not, the global middleware will be loaded automatically, and the local middleware needs to be specified on the API route manually
dependencies Indicate which middlewares this middleware relies on to load after those middlewares. Generally, it depends on middleware instance, because middleware instance provides the basic logic of multi-instance

2. Definition of Middleware Bean Component

src/suite-vendor/test-party/modules/test-party/backend/src/bean/middleware.interception.js

  1. 1module.exports = ctx => {
  2. 2 class Middleware {
  3. 3 async execute(options, next) {
  4. 4 const { a, b } = ctx.request.body;
  5. 5 if (a === undefined || b === undefined) return ctx.throw(1002); // 1002: 'Incomplete Parameters'
  6. 6 // next
  7. 7 await next();
  8. 8 }
  9. 9 }
  10. 10 return Middleware;
  11. 11};

src/suite-vendor/test-party/modules/test-party/backend/src/bean/middleware.restructuring.js

  1. 1module.exports = ctx => {
  2. 2 class Middleware {
  3. 3 async execute(options, next) {
  4. 4 const { a, b } = ctx.request.body;
  5. 5 ctx.request.body.a = parseInt(a);
  6. 6 ctx.request.body.b = parseInt(b);
  7. 7 // next
  8. 8 await next();
  9. 9 }
  10. 10 }
  11. 11 return Middleware;
  12. 12};

3. Register Middleware Bean Component

src/suite-vendor/test-party/modules/test-party/backend/src/beans.js

  1. 1const middlewareTestInterception = require('./bean/middleware.interception.js');
  2. 2const middlewareTestRestructuring = require('./bean/middleware.restructuring.js');
  3. 3
  4. 4module.exports = app => {
  5. 5 const beans = {
  6. 6 // middleware
  7. 7 'middleware.testInterception': {
  8. 8 mode: 'ctx',
  9. 9 bean: middlewareTestInterception,
  10. 10 },
  11. 11 'middleware.testRestructuring': {
  12. 12 mode: 'ctx',
  13. 13 bean: middlewareTestRestructuring,
  14. 14 },
  15. 15 };
  16. 16 return beans;
  17. 17};

Usage of Middleware

1. Config API Route

Because testInterception and testRestructuring are local middlewares, you need to specify it manually on the API route

src/suite-vendor/test-party/modules/test-party/backend/src/routes.js

  1. 1// test/feat/middleware
  2. 2{ method: 'post', path: 'test/feat/middleware/interception', controller: 'testFeatMiddleware', middlewares: 'test,testInterception' },
  3. 3{ method: 'post', path: 'test/feat/middleware/restructuring', controller: 'testFeatMiddleware', middlewares: 'test,testInterception,testRestructuring' },

2. Backend Logic

src/suite-vendor/test-party/modules/test-party/backend/src/controller/test/feat/middleware.js

  1. 1module.exports = app => {
  2. 2
  3. 3 class TestController extends app.Controller {
  4. 4
  5. 5 async interception() {
  6. 6 const { a, b } = this.ctx.request.body;
  7. 7 const c = parseInt(a) + parseInt(b);
  8. 8 this.ctx.success(c);
  9. 9 }
  10. 10
  11. 11 async restructuring() {
  12. 12 const { a, b } = this.ctx.request.body;
  13. 13 const c = a + b;
  14. 14 this.ctx.success(c);
  15. 15 }
  16. 16
  17. 17 }
  18. 18
  19. 19 return TestController;
  20. 20};

src/suite-vendor/test-party/modules/test-party/backend/src/controllers.js

  1. 1const testFeatMiddleware = require('./controller/test/feat/middleware.js');
  2. 2
  3. 3module.exports = app => {
  4. 4 const controllers = {
  5. 5 testFeatMiddleware,
  6. 6 };
  7. 7 return controllers;
  8. 8};

Unit-Test

Here, we use unit-tests to verify that the middleware mechanism works as expected

src/suite-vendor/test-party/modules/test-party/backend/test/controller/test/feat/middleware.test.js

  1. 1const { app, mockUrl, mockInfo, assert } = require('egg-born-mock')(__dirname);
  2. 2
  3. 3describe('test/controller/test/feat/middleware.test.js', () => {
  4. 4
  5. 5 it('action:interception', async () => {
  6. 6 // success
  7. 7 let result = await app.httpRequest()
  8. 8 .post(mockUrl('test/feat/middleware/interception'))
  9. 9 .send({
  10. 10 a: '1',
  11. 11 b: '2',
  12. 12 });
  13. 13 assert.equal(result.body.data, 3);
  14. 14
  15. 15 // fail
  16. 16 result = await app.httpRequest()
  17. 17 .post(mockUrl('test/feat/middleware/interception'))
  18. 18 .send();
  19. 19 assert.equal(result.status, 500);
  20. 20 });
  21. 21
  22. 22 it('action:restructuring', async () => {
  23. 23 // success
  24. 24 const result = await app.httpRequest()
  25. 25 .post(mockUrl('test/feat/middleware/restructuring'))
  26. 26 .send({
  27. 27 a: '1',
  28. 28 b: '2',
  29. 29 });
  30. 30 assert.equal(result.body.data, 3);
  31. 31 });
  32. 32
  33. 33});