matchMock.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. const mockFile = require('./mock/index');
  2. const pathToRegexp = require('path-to-regexp');
  3. const debug = console.log;
  4. const bodyParser = require('body-parser');
  5. const BODY_PARSED_METHODS = ['post', 'put', 'patch'];
  6. function parseKey(key) {
  7. let method = 'get';
  8. let path = key;
  9. if (key.indexOf(' ') > -1) {
  10. const splited = key.split(' ');
  11. method = splited[0].toLowerCase();
  12. path = splited[1]; // eslint-disable-line
  13. }
  14. return {
  15. method,
  16. path,
  17. };
  18. }
  19. function createHandler(method, path, handler) {
  20. return function(req, res, next) {
  21. if (BODY_PARSED_METHODS.includes(method)) {
  22. bodyParser.json({ limit: '5mb', strict: false })(req, res, () => {
  23. bodyParser.urlencoded({ limit: '5mb', extended: true })(req, res, () => {
  24. sendData();
  25. });
  26. });
  27. } else {
  28. sendData();
  29. }
  30. function sendData() {
  31. if (typeof handler === 'function') {
  32. handler(req, res, next);
  33. } else {
  34. res.json(handler);
  35. }
  36. }
  37. };
  38. }
  39. function normalizeConfig(config) {
  40. return Object.keys(config).reduce((memo, key) => {
  41. const handler = config[key];
  42. const { method, path } = parseKey(key);
  43. const keys = [];
  44. const re = pathToRegexp(path, keys);
  45. memo.push({
  46. method,
  47. path,
  48. re,
  49. keys,
  50. handler: createHandler(method, path, handler),
  51. });
  52. return memo;
  53. }, []);
  54. }
  55. const mockData = normalizeConfig(mockFile);
  56. function matchMock(req) {
  57. const { path: exceptPath } = req;
  58. const exceptMethod = req.method.toLowerCase();
  59. for (const mock of mockData) {
  60. const { method, re, keys } = mock;
  61. if (method === exceptMethod) {
  62. const match = re.exec(req.path);
  63. if (match) {
  64. const params = {};
  65. for (let i = 1; i < match.length; i = i + 1) {
  66. const key = keys[i - 1];
  67. const prop = key.name;
  68. const val = decodeParam(match[i]);
  69. if (val !== undefined || !hasOwnProperty.call(params, prop)) {
  70. params[prop] = val;
  71. }
  72. }
  73. req.params = params;
  74. return mock;
  75. }
  76. }
  77. }
  78. function decodeParam(val) {
  79. if (typeof val !== 'string' || val.length === 0) {
  80. return val;
  81. }
  82. try {
  83. return decodeURIComponent(val);
  84. } catch (err) {
  85. if (err instanceof URIError) {
  86. err.message = `Failed to decode param ' ${val} '`;
  87. err.status = err.statusCode = 400;
  88. }
  89. throw err;
  90. }
  91. }
  92. return mockData.filter(({ method, re }) => {
  93. return method === exceptMethod && re.test(exceptPath);
  94. })[0];
  95. }
  96. module.exports = (req, res, next) => {
  97. const match = matchMock(req);
  98. if (match) {
  99. debug(`mock matched: [${match.method}] ${match.path}`);
  100. return match.handler(req, res, next);
  101. } else {
  102. return next();
  103. }
  104. };