Синхронизируйте локальные фиктивные данные с помощью документа интерфейса пользовательского интерфейса Swagger.

Node.js задняя часть внешний интерфейс Swagger NPM

Что такое Мок

Mock, как следует из названия, представляет собой симуляцию. Обычно тот же интерфейс используется для имитации объекта вместо реального объекта, что позволяет эффективно изолировать внешние зависимости и облегчить тестирование. Для фронтенд-разработки Mock, как важная часть, может принести множество преимуществ:

  • Front-end и back-end параллельная разработка
  • Имитирует различные значения отклика для легкого тестирования
  • Он может заранее обнаруживать некоторые проблемы с макетом страницы при экстремальных значениях отклика и т. д.

задний план

Фронтенд-разработку можно условно разделить на три этапа: этап параллельной разработки, этап совместной отладки и этап тестирования. Большинство текущих фронтенд-проектов отделены от фронтенда и бэкенда, и неизбежно столкновение с проблемой источников данных на этапах разработки и совместной отладки.

前端开发阶段

На этапе совместной отладки в каждой среде есть реальные данные, что удобно для локальной отладки, обычно мы указываем интерфейс на реальный источник данных. Если существуют междоменные ограничения, вы можете использовать отладочные прокси-инструменты, такие как Charles и Fiddler, чтобы решить эту проблему, или вы можете запустить локальный сервер:

const express = require('express');
const proxy = require('http-proxy-middleware');
const app = express();

app.use('/api', proxy({ target: 'your-api-url', changeOrigin: true }));
app.listen(3000);

Если он все еще находится в стадии параллельной разработки, то нам нужны Mock-данные.В целом, есть следующие распространенные методы:

1. Перехватывать запросы Ajax и Fetch
Недостатки: Грязный код, смешанный во внешнем интерфейсе, не может эффективно имитировать сетевые условия.

2. Локальный фиктивный сервер
Недостатки: Интерфейсов много, а стоимость создания и модификации высока.

3. Платформа управления интерфейсом YApi и Easy Mock
Недостаток: недостаточно гибкий. Например, по каждому интерфейсу разбросана некоторая информация о конфигурации, которой нельзя управлять централизованно, а стоимость модификации высока.

В этой статье Swagger, с которым автор много раз сталкивался, используется в качестве примера для исправления недостатков локального Mock Server, которому необходимо постоянно создавать интерфейсы с одной стороны. Откройте сеть адреса пользовательского интерфейса Swagger, предоставленного серверной частью, и найдите файл API-docs.

接口文档

Этот файл JSON содержит такую ​​информацию, как интерфейс, метод запроса и формат ответа. Можно представить, что парсить этот файл не сложно, единственное хлопотное дело может быть парсинг и преобразование типа значения ответа. Если вы сможете своевременно синхронизировать данные с локальным фиктивным сервером, вы сможете сэкономить много утомительной физической работы.

Talk is cheap

1. Цели

  • Путь к интерфейсу соответствует каталогу Mock, который легко найти и изменить.
  • С методом запроса в качестве имени файла один метод соответствует одному файлу, что снижает конфликты при редактировании несколькими людьми.
  • Используйте Mock.js для переноса значений ответов, чтобы легко имитировать некоторые экстремальные ситуации.

2. Разберите файл JSON

Ранее мы упоминали, что сложность парсинга файлов JSON в основном заключается в преобразовании типов значений ответа, здесь для этого мы используем модуль парсинга Easy Mock.

const swaggerParserMock = require('swagger-parser-mock');

const synchronizeSwagger = {
  init({ url, blacklist, outputPath }) {
    this.url = url;
    this.blacklist = blacklist;
    this.outputPath = outputPath;
    this.parse();
  },
  async parse() {
    const { paths } = await swaggerParserMock(this.url);
    this.generate(paths);
    console.log(paths);
  }
}

synchronizeSwagger.init({
  // Swagger api-docs地址
  "url": "your-api-docs-url",
  // 输出目录
  "outputPath": "./routes",
  // 黑名单,跳过一些不需要同步的api
  "blacklist": []
});

Информация о путях печати, формат примерно следующий:

"/path/foo": {
  "get": {
    "summary": "bar",
    "responses": {
      "200": {
        "example": "'@string'" // 模块为我们做的类型转化和Mock.js包装。
      }
    }
  },
  "post": {
    "summary": "baz",
    "responses": {
      "200": {
        "example": "'@string'"
      }
    }
  }
}

3. Пройдитесь по интерфейсу. Мы можем добавить черный список, чтобы отфильтровать некоторые интерфейсы, которые бесполезны для внешнего интерфейса. Уменьшите количество сбоев и улучшите ремонтопригодность.

const fs = require('fs');
const { join } = require('path');
const { promisify } = require('util');
const mkdirp = require('mkdirp');

const writeFile = promisify(fs.writeFile);
const mkdir = promisify(mkdirp);

const synchronizeSwagger = {
  // 遍历api path信息
  traverse(paths) {
    for (let path in paths) {
      if (this.blacklist.includes(path)) {
        continue;
      }

      for (let method in paths[path]) {
        const pathInfo = paths[path][method];

        if (!pathInfo['responses']['200']) {
          continue;
        }
        this.generate(path, method, pathInfo);
      }
    }
  }
}

4. Создайте Mock-файл, в который можно добавить комментарии и другую информацию.

const synchronizeSwagger = {
  // 生成mock文件
  async generate(path, method, pathInfo) {
    const outputPath = join(__dirname, this.outputPath, path);
    const {
      summary,
      responses: { 200: responseOK },
    } = pathInfo;

    try {
      // 生成目录
      await mkdir(outputPath);

      const example = responseOK['example'];
      // 生成文件内容
      const template = this.generateTemplate({
        summary,
        example,
        method,
        path,
      });

      // 生成文件, 已存在的跳过,避免覆盖本地以及编辑的文件
      const fPath = join(outputPath, `${method}.js`);
      await writeFile(fPath, template, { flag: 'wx' });
      console.log(`增加Mock文件:${fPath}`);
    } catch (error) {
      /* eslint-disable no-empty */
    }
  },

  generateTemplate({ summary, example, method, path }) {
  // prettier-ignore
  // api path中的{petId}形式改为:petId
  return `/**
${summary}
**/
const Mock = require("mockjs");
module.exports = function (app) {
  app.${method}('/api${path.replace(/\{([^}]*)\}/g, ":$1")}', (req, res) => {
    res.json(Mock.mock(${example}));
  });
};`;
  },
}

5. Запустите фиктивный сервер

Взяв в качестве примера экспресс, мы используем динамическую функцию require для создания маршрута, который сопоставляется с только что созданным файлом интерфейса.

const fs = require('fs');
const join = require('path').join;
const express = require('express');

const app = express();
const port = process.env.PORT || 3000;

app.listen(port, function() {
  console.log(`server is listening ${port}`);
});

function scan(path, app) {
  const files = fs.readdirSync(path);

  for (let i = 0; i < files.length; i++) {
    const fpath = join(path, files[i]);
    const stats = fs.statSync(fpath);

    if (stats.isDirectory()) {
      scan(fpath, app);
    }
    if (stats.isFile()) {
      require(fpath)(app);
    }
  }
}

scan(join(__dirname, './routes'), app);

напиши в конце

До сих пор мы использовали пользовательский интерфейс Swagger для синхронизации данных Mock.Если мы добавим промежуточное программное обеспечение, такое как cors и body-parser, в основном формируется локальный сервер Mock. Для облегчения синхронизации мы добавляем его в скрипты npm.

  "scripts": {
    "ss": "node ./synchronizeSwagger.js"
  },

Выполните npm run ss, чтобы сгенерировать соответствующие фиктивные данные и интерфейс доступа.

route

api

Приложение:образец кода