Использовали ли вы Swagger/OpenAPI для документирования API в Node.js?

Ответ

Да, активно использовал Swagger (OpenAPI 3.0) для документирования REST API в Node.js проектах. Предпочитаю подход с swagger-jsdoc, который позволяет держать документацию рядом с кодом.

Моя типичная настройка:

// swagger.js - конфигурация Swagger
const swaggerJsdoc = require('swagger-jsdoc');

const options = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'E-commerce API',
      version: '1.0.0',
      description: 'Документация API для интернет-магазина',
      contact: {
        name: 'API Support',
        email: 'support@example.com'
      }
    },
    servers: [
      {
        url: 'https://api.example.com/v1',
        description: 'Production server'
      },
      {
        url: 'http://localhost:3000/api/v1',
        description: 'Development server'
      }
    ],
    components: {
      securitySchemes: {
        BearerAuth: {
          type: 'http',
          scheme: 'bearer',
          bearerFormat: 'JWT'
        }
      },
      schemas: {
        User: {
          type: 'object',
          required: ['email', 'name'],
          properties: {
            id: {
              type: 'string',
              format: 'uuid',
              example: '550e8400-e29b-41d4-a716-446655440000'
            },
            email: {
              type: 'string',
              format: 'email',
              example: 'user@example.com'
            },
            name: {
              type: 'string',
              example: 'John Doe'
            }
          }
        }
      }
    }
  },
  apis: ['./src/routes/*.js', './src/models/*.js'] // Пути к файлам с JSDoc
};

const specs = swaggerJsdoc(options);
module.exports = specs;

Пример документации роута с JSDoc:

// routes/users.js
/**
 * @swagger
 * /api/v1/users:
 *   get:
 *     summary: Получить список пользователей
 *     description: Возвращает список пользователей с пагинацией
 *     tags:
 *       - Users
 *     parameters:
 *       - in: query
 *         name: page
 *         schema:
 *           type: integer
 *           default: 1
 *         description: Номер страницы
 *       - in: query
 *         name: limit
 *         schema:
 *           type: integer
 *           default: 20
 *         description: Количество записей на странице
 *     responses:
 *       200:
 *         description: Успешный ответ
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 data:
 *                   type: array
 *                   items:
 *                     $ref: '#/components/schemas/User'
 *                 pagination:
 *                   $ref: '#/components/schemas/Pagination'
 */
router.get('/', UserController.getAllUsers);

Подключение Swagger UI в Express:

// app.js
const express = require('express');
const swaggerUi = require('swagger-ui-express');
const specs = require('./swagger');

const app = express();

// Swagger UI
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs, {
  explorer: true,
  customCss: '.swagger-ui .topbar { display: none }',
  customSiteTitle: 'API Documentation'
}));

// Также добавлял эндпоинт для raw спецификации
app.get('/api-docs.json', (req, res) => {
  res.json(specs);
});

Преимущества, которые я получил:

  1. Автоматическая документация: При изменении кода документация обновляется автоматически
  2. Интерактивное тестирование: Frontend-разработчики могли тестировать API прямо из браузера
  3. Генерация клиентского кода: Использовал swagger-codegen для автоматической генерации TypeScript-клиентов
  4. Валидация запросов: Интегрировал с express-openapi-validator для автоматической валидации входящих запросов по схеме OpenAPI

Также использовал Swagger для документирования WebSocket endpoints и GraphQL API (через расширения OpenAPI).

Ответ 18+ 🔞

А, ну это про Swagger! Да, я с этой штукой работал, ебать мои старые костыли. OpenAPI 3.0, если конкретно. Документировал им REST API в Node.js проектах. Подход у меня был такой — юзал swagger-jsdoc, чтобы документация прямо в коде жила, а не где-то на отшибе. Удобно же, всё в одном месте, не надо бегать между файлами.

Вот как я обычно настраивал эту бандуру:

// swagger.js - конфигурация Swagger
const swaggerJsdoc = require('swagger-jsdoc');

const options = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'E-commerce API',
      version: '1.0.0',
      description: 'Документация API для интернет-магазина',
      contact: {
        name: 'API Support',
        email: 'support@example.com'
      }
    },
    servers: [
      {
        url: 'https://api.example.com/v1',
        description: 'Production server'
      },
      {
        url: 'http://localhost:3000/api/v1',
        description: 'Development server'
      }
    ],
    components: {
      securitySchemes: {
        BearerAuth: {
          type: 'http',
          scheme: 'bearer',
          bearerFormat: 'JWT'
        }
      },
      schemas: {
        User: {
          type: 'object',
          required: ['email', 'name'],
          properties: {
            id: {
              type: 'string',
              format: 'uuid',
              example: '550e8400-e29b-41d4-a716-446655440000'
            },
            email: {
              type: 'string',
              format: 'email',
              example: 'user@example.com'
            },
            name: {
              type: 'string',
              example: 'John Doe'
            }
          }
        }
      }
    }
  },
  apis: ['./src/routes/*.js', './src/models/*.js'] // Пути к файлам с JSDoc
};

const specs = swaggerJsdoc(options);
module.exports = specs;

А вот пример, как я роут документировал с помощью JSDoc:

// routes/users.js
/**
 * @swagger
 * /api/v1/users:
 *   get:
 *     summary: Получить список пользователей
 *     description: Возвращает список пользователей с пагинацией
 *     tags:
 *       - Users
 *     parameters:
 *       - in: query
 *         name: page
 *         schema:
 *           type: integer
 *           default: 1
 *         description: Номер страницы
 *       - in: query
 *         name: limit
 *         schema:
 *           type: integer
 *           default: 20
 *         description: Количество записей на странице
 *     responses:
 *       200:
 *         description: Успешный ответ
 *         content:
 *           application/json:
 *             schema:
 *               type: object
 *               properties:
 *                 data:
 *                   type: array
 *                   items:
 *                     $ref: '#/components/schemas/User'
 *                 pagination:
 *                   $ref: '#/components/schemas/Pagination'
 */
router.get('/', UserController.getAllUsers);

Ну и подключение Swagger UI в Express, куда ж без него:

// app.js
const express = require('express');
const swaggerUi = require('swagger-ui-express');
const specs = require('./swagger');

const app = express();

// Swagger UI
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs, {
  explorer: true,
  customCss: '.swagger-ui .topbar { display: none }',
  customSiteTitle: 'API Documentation'
}));

// Также добавлял эндпоинт для raw спецификации
app.get('/api-docs.json', (req, res) => {
  res.json(specs);
});

Чего я с этого всего имел, ёпта? Овердохуища плюшек:

  1. Документация сама себя пишет. Изменил код — она обновилась, не надо руками всё переписывать, как будто на дворе 2002-й год.
  2. Тестировать можно прямо в браузере. Фронтендеры подходят, такие: «А как этот ваш API работает?» — а ты им: «Вот, хуй с горы, сам потестируй». И правда, всё интерактивно.
  3. Клиентский код генерился автоматом. Юзал swagger-codegen — и на тебе, TypeScript-клиенты готовы, не надо их вручную писать, ебать колотить.
  4. Валидация запросов по схеме. Интегрировал с express-openapi-validator — и всё, прилетает запрос не по схеме, ему сразу отлуп, даже до контроллера не доходит. Красота.

А ещё, представляешь, Swagger-ом и WebSocket endpoints документировал, и даже GraphQL API (через расширения OpenAPI). В общем, инструмент универсальный, если руки из правильного места.