matchMock.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. const pathToRegexp = require('path-to-regexp');
  2. const bodyParser = require('body-parser');
  3. const mockFile = require('./mock/index');
  4. const BODY_PARSED_METHODS = ['post', 'put', 'patch'];
  5. const debug = console.log;
  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 (req, res, next) => {
  21. function sendData() {
  22. if (typeof handler === 'function') {
  23. handler(req, res, next);
  24. } else {
  25. res.json(handler);
  26. }
  27. }
  28. if (BODY_PARSED_METHODS.includes(method)) {
  29. bodyParser.json({ limit: '5mb', strict: false })(req, res, () => {
  30. bodyParser.urlencoded({ limit: '5mb', extended: true })(req, res, () => {
  31. sendData();
  32. });
  33. });
  34. } else {
  35. sendData();
  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. function decodeParam(val) {
  60. if (typeof val !== 'string' || val.length === 0) {
  61. return val;
  62. }
  63. try {
  64. return decodeURIComponent(val);
  65. } catch (err) {
  66. if (err instanceof URIError) {
  67. err.message = `Failed to decode param ' ${val} '`;
  68. err.statusCode = 400;
  69. err.status = 400;
  70. }
  71. throw err;
  72. }
  73. }
  74. // eslint-disable-next-line no-restricted-syntax
  75. for (const mock of mockData) {
  76. const { method, re, keys } = mock;
  77. if (method === exceptMethod) {
  78. const match = re.exec(req.path);
  79. if (match) {
  80. const params = {};
  81. for (let i = 1; i < match.length; i += 1) {
  82. const key = keys[i - 1];
  83. const prop = key.name;
  84. const val = decodeParam(match[i]);
  85. if (val !== undefined || !hasOwnProperty.call(params, prop)) {
  86. params[prop] = val;
  87. }
  88. }
  89. req.params = params;
  90. return mock;
  91. }
  92. }
  93. }
  94. return mockData.filter(({ method, re }) => method === exceptMethod && re.test(exceptPath))[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. }
  102. return next();
  103. };