В современных реалиях разработки программного обеспечения бывает достаточно трудно быстро и качественно написать техническую документацию к проекту, особенно когда данному процессу уделяется недостаточно времени по разным причинам: от временных ограничений, до индивидуальной непереносимости монотонного процесса участниками проектной группы, который, порой, может тормозить рабочие процессы. Уже сейчас существуют инструменты, которые позволяют ускорить процесс документирования программного обеспечения. Эти инструменты значительно облегчают задачи разработчиков по ведению технической документации и внесению быстрых правок, что позволяет отражать в документации актуальные положения фактического поведения системы. В данной статье будет рассмотрен один из таких инструментов. Основное внимание в статье будет уделено автоматизации процесса создания документации API сервисов, которые разрабатываются с помощью фреймворков Express.js и Gin, используя подходящий для этой задачи инструмент - Swagger. В качестве основного источника мотивации для написания данной статьи я избрал свой личный опыт разрешения проблем с быстрым и удобным документированием API сервисов, с которыми мне пришлось столкнуться при разработке сервисов на Express.js. Данным опытом я хотел бы поделиться с читателем, так как нахожу его полезным и, возможно, он принесёт пользу разработчикам, которые столкнулись с аналогичными проблемами. Под сервисом в статье подразумевается любое серверное приложение, которое принимает запросы на определённом порту и возвращает ответ после проведения определённых манипуляций с данными. В статье наибольшее внимание уделено именно практическим задачам, в рамках программирования сервисов, потому здесь может отсутствовать более подробное теоретическое изложение некоторых технологий или концепций, но на них будут оставлены ссылки для более детального ознакомления.  В конце статьи будут приведены ссылки на исходный код, который использовался в целях продемонстрировать возможности рассматриваемых пакетов и используемых скриптов. Код данных проектов следует рассматривать исключительно как пример, а не полноценно работающие приложения. Swagger - это профессиональный набор инструментов для разработчиков API. Данный набор инструментов активно разрабатывается SmartBear Software и поддерживается сообществом открытого исходного кода (Open Source).  OpenAPI - это спецификация для описания API. На текущий момент времени актуальная версия OpenAPI - 3.1.0. Swagger использует спецификацию OpenAPI для описания и документирования API, а инструменты Swagger позволяют использовать эту спецификацию для создания и тестирования API, а также для генерации клиентского кода. Набор инструментов Swagger включает в себя следующие наиболее используемые инструменты: Swagger Editor - редактор для разработки API-интерфейсов в соответствии со спецификацией Open API Swagger UI - веб-приложение, позволяющая визуализировать определения спецификаций Open API в интерактивном пользовательском интерфейсе Swagger Codegen - создание серверных заглушек и клиентских SDK-пакетов на основе определений спецификаций Open API Этим списком весь набор Swagger не заканчивается, их достаточно много. Читателю предлагается ознакомиться со всем набором инструментов на официальном сайте. Из вышеприведённого списка наиболее интересным инструментом является Swagger Editor, поскольку он предоставляет интерфейс для создания файла документации по спецификации Open API вручную. Однако, перед началом рассмотрения инструмента Swagger Editor следует ответить на вопрос, а что же мы, собственно, собираемся документировать? API слишком общее понятие, следует конкретизировать что именно мы собираемся документировать. И в этом может помочь архитектурный паттерн Controller Service Repository. Controller Service Repository (CSR) - архитектурный паттерн, который помогает разделить ответственность между слоями приложения и соблюдать принципы SOLID. Само определение паттерна содержит три важных элемента: Controller - слой классов, отвечающих за обработку запросов (в частности - пользовательских). В данных классах происходит получение запроса от клиента (request), валидация входных данных (если она подразумевалась), передача данных конкретному сервису, обработка ошибок и формирование ответа пользователю (response). Service - слой классов, отвечающих за бизнес-логику приложения. В сервисах отсутствуют прямые обращения к базе данных - данная функция делегируется репозиториям, которые завершают это перечисление. Repository - слой классов, отвечающих за сохранение и извлечение некоторого набора данных. В репозиториях не должно быть бизнес-логики. В методах репозитория должны лишь формироваться и выполняться запросы к базе данных. Удобно представлять эти слои в виде сферы из разных слоёв, каждый из которых по цепочки находится "ближе к данным" (постепенное уменьшение уровня абстракции над взаимодействием с базой данных).  На рисунке ниже представлена данная модель. Причём здесь данный архитектурный паттерн? Дело в том, что данный паттерн является одним из самых популярных на сегодняшний день и отлично подходит для объяснения момента, с которого начинается документирование API (определение этой границы). Все API, как правило, определяются в объединении множества маршрутов и конкретных обработчиков в слое Controller (иными словами - привязка конкретного метода из любого класса слоя Controller, к конкретному маршруту). Следовательно, в слое Controller и происходит документирование API. Возможны комбинации, но в основном это можно принять как правило. Это будет рассмотрено на практике более детально. Как уже ранее упоминалось Swagger Editor позволяет визуализировать документацию в соответствии с описанием по спецификации OpenAPI. Каким образом представлено данное описание? В формате YAML. Грубо говоря вся документация проекта будет представлена в виде одного файла с расширением yaml. Это очень удобно, ведь при необходимости этот документ можно перенести куда угодно, при этом он будет однозначно интерпретирован рассматриваемым набором инструментов, т.к. существует единый стандарт (а в случае проблем с соответствием стандарту инструменты будут выдавать сообщения об ошибках). На рисунке ниже представлена работа Swigger Editor. Данные, представленные в формате YAML, можно изменять и тогда в Swagger Editor будут отображаться все изменения. Теоретически можно самостоятельно описать все API в своём сервисе с помощью данного инструмента и просто передавать файл с расширением yaml между разработчиками, чтобы они сами у себя запускали веб-приложение Swagger UI и указывали источником данных этот файл, однако данный подход крайне неудобен. Даже сейчас файл документации содержит порядка 800 строк, что довольно громоздко для количества маршрутов и их сложности, представленных в качестве базового примера в Swagger Editor. Как можно решить проблему с ручным документированием API? Автоматизировать данный процесс. Тут мы приступаем к рассмотрению практической части. Всего будет два сервиса, которые схожи между собой функционалом. Предположим, что перед нами была поставлена задача разработать сервис авторизации пользователя. Один сервис будет использовать технологический стек Node.js, Express.js, JavaScript, а другой - Gin, Golang. Первый сервис будет иметь кодовое название NEJ, а второй - GG. Опустим момент с моделированием базы данных каждого сервиса, что рекомендуется своевременно делать при более серьёзной разработке подобного рода сервисов. Приступим к разработке сервиса с кодовым названием NEJ. Для начала изучим файловую структуру проекта. В файловой структуре проекта определены следующие директории и файлы (только основные элементы): config - директория, содержащая конфигурационные файлы сервиса constants - директория с общими константами controllers - директория, содержащая контроллеры (слой Controller) db - директория с настройками подключения к базе данных и определением моделей docs - документация сервиса (*.yaml) dtos - директория, содержащая DTO exceptions - директория, содержащая основные ошибки сервиса (классы для обработки ошибок) logger - настройки логгера logs - логи сервиса middlewares - промежуточное программное обеспечение (используется для проверки токенов JWT и обработки исключений) routers - директория, содержащая конкретные привязки методов контроллеров с конкретными маршрутами (url-адресами) services - директория, содержащая сервисы (слой Services) utils - директория с утилитами *.env - файлы с переменными окружения generate-doc.js - скрипт, для автоматической генерации документации API index.js - точка входа в серверное приложение wipe-dependencies.js - скрипт, для автоматического обновления пакетов в package.json Далее, опишем основные элементы данного сервиса, начиная с точки входа и скрипта для автоматического документирования. Код точки входа в серверное приложение выглядит следующим образом: Далее последуют объяснения кода из точки входа в NEJ. Сперва происходит загрузка файла документации в формате YAML в переменную swaggerDocument Это даёт нам возможность визуализировать документацию с помощью пакета swagger-ui-express. Перейдём к рассмотрению привязки данного файла к Swagger UI На данном коде происходит привязка Swagger UI к маршруту "/docs". Когда пользователь переходит по этому маршруту, будет показан интерфейс Swagger UI с предоставленной документацией, которая описывает активности и доступные ресурсы API этого сервиса. Swagger UI обеспечивает удобное взаимодействие с API, позволяя отправлять запросы и просматривать ответы в реальном времени. На рисунке ниже представлена работа по данному маршруту Swagger UI. Как видно из рисунка всё действительно работает, более того - отображается документация в спецификации OpenAPI 3.  Внимательный читатель может отметить в коде точки входа, что есть отдельный опциональный блок, который позволяет увидеть документацию в более ранней спецификации (OpenAPI 2). Однако, зачем это необходимо? Ответ прост - демонстрация исходной документации Swagger, которая была первоначально сгенерирована. Дело в том, что документация по умолчанию генерируется по спецификации OpenAPI 2, т.к. это особенности используемого пакета. Для автоматической генерации документации по контроллерам был использован пакет express-swagger-generator, который не пользуется большой популярностью в статьях подобного характера (Swagger, Express.js). Данный пакет отлично справился с задачей автоматической генерации документации. Ссылка на официальную документацию.  Приступим к обзору скрипта, который производит автоматическую генерацию документации в спецификацию OpenAPI 2, а затем конвертирует её в спецификацию OpenAPI 3. Ниже представлен скрипт автоматической генерации документации API Немного разъясним работу данного скрипта. Он запускается через отдельный скрипт в package.json, а именно - с помощью npm run generate:doc После генерации документации в файл docs_swagger2.yaml добавляется сгенерированные данные в формате yaml, согласно спецификации OpenAPI 2  Также в скрипте идёт процесс конвертации файла с спецификацией OpenAPI 2, в файл с спецификацией OpenAPI 3 Соответственно после конвертации появится файл docs.yaml, в котором будет содержимое уже в спецификации OpenAPI 3.0  Чтобы убедиться в работоспособности данной документации можно вставить содержимое файла docs.yaml в Swagger Editor Все используемые пакеты в сервисе NEJ представлены в удалённом репозитории.  Перейдём к функциональным особенностям пакета express-swagger-generator. Все настройки для Swagger'а, которые используются при генерации документации по спецификации OpenAPI 2 представлены в файле /config/swagger.options.js С помощью options подключаемый модуль express-swagger-generator понимает, каким образом генерировать документацию, какие файлы учитывать (по каком файлам делать обход), по какому маршруту нужно выводить документацию, определяет основную информацию на странице документации и так далее. Ранее мы уже определили, что документирование API начинается с контроллеров, а если быть точнее - роутеров, которые связывают конкретные адреса с контроллерами. Пора продемонстрировать каким образом пакет express-swagger-generator помогает составить документацию, используя классический JSDoc. Разберём документирование API на примере POST-запроса на регистрацию нового пользователя. Можно заметить, что описание для данного API представлено в виде последовательности комментариев: Эти комментарии по структуре похожи на JSDoc-комментарии, однако их интерпретация используемым пакетом осуществляется по своему. Дадим разъяснения данным комментариям: В первой строке многострочного комментария представлено описание конкретного API @ route POST /auth/sign-up - привязка API к текущему адресу в документации @ group Авторизация ... - соотнесение данного API к конкретной группе (аналогично, что и tag) @ param {SignUpDto.model} input.body.required - определение модели входных данных (без необходимости в ссылках #ref, по спецификации OpenAPI) @ returns {AuthDto.model} 200 - описание модели выходных данных (при успешной обработке запроса) @ return {ApiError.model} default - обработка всех ошибок по умолчанию Каким образом формируются модели? Приведу пример с моделью SignUpDto: Интересует именно описание в многострочном комментарии: Дадим пояснение данному определению: @ typedef SignUpDto - определение модели (схемы) SignUpDto (на которую потом можно будет ссылаться) @ property {string} email.required - определение параметра email, с типом string Остальное - по аналогии со вторым элементом из списка Также можно сделать более сложное определение: Дадим пояснения тому, что есть в многострочном комментарии: @ typedef AuthDto - создание модели AuthDto @ property {TokenDto.model} tokens.required - создание параметра в модели, которое по сути является другой моделью (вложенность схем) Далее - по аналогии Необязательно многострочные комментарии с определением моделей держать рядом с моделями, можно держать их и отдельно. Например, следующее определение будет работать корректно: Однако, рекомендуется держать определение моделей в многострочных комментариях держать с их фактическим местоположением, ради достижения модульности, ведь в настройках этот момент учтён. Изучим файловую структуру проекта GG Приведу пояснения по файловой структуре проекта (только основные элементы): cmd - директория, в которой определена точка входа в серверное приложение (main.go) config - директория с файлами конфигурации database - директория, в которой содержатся схемы и дампы базы данных docs - директория, в которой располагается сгенерированная документация logs - логи сервера pkg - основные пакеты сервиса server.go - определение сервера Код точки входа в серверное приложение GG выглядит следующим образом: В данной точке входа основной интерес вызывает множество комментариев, которые задают базовые настройки для вывода Swagger-документации (аналогично замыканию options из сервиса NEJ). В данных комментариях содержится та же информация, что и содержалось в options для сервиса NEJ. Пакет, который используется для автоматического документирования API маршрутов, называется swag. Данный пакет позволяет быстро и эффективно определить любой API. Прежде чем приступить к обозреванию того, каким образом необходимо документировать API, подробнее разберём файловую структуру проекта, чтобы убедиться соответствию её архитектурному паттерну CSR. В директории присутствует каталог handler (обработчики, они же - контроллеры), repository и service. Минимум необходимого для CSR наблюдается. Если связь контроллеров с определённым адресом формируется в handler, то там и следует описывать API. Приведу пример документирования одного из маршрутов сервиса - авторизация пользователя. Наибольший интерес представляют комментарии: Здесь структура отличается от той, которая была использована в сервисе NEJ. В данном случае используется однострочный комментарий. Поясним некоторые параметры при описании API: @ Summary - название запроса в документации @ Tags - теги для группировки API @ Description - описание запроса в документации @ ID - идентификатор API @ Accept - данные, которые будут приниматься на входе запроса @ Produce - формат данных, которые будут возвращаться в ответе @ Param input body userModel.UserSignInModel - параметры запроса @ Success 200 {object} userModel.TokenAccessModel "data" - код ответа, формат данных и описание @ Failure 400,404 {object} httpModel.ResponseMessage - код ответа, формат данных и описание @ Router /auth/sign-in [post] - путь запроса и метод запроса(HTTP)  Для генерации документации достаточно выполнить команду swag init -g cmd/main.go Также важно, чтобы перед генерацией документации был определён маршрут, по которому будет осуществлён вывод документации, сгенерированной локально: Код добавления просмотра документации по определённому пути выглядит следующим образом: При запуске сервиса мы получим возможность просмотра документации онлайн. В рамках данной статьи были описаны два сервиса, которые использовали инструментарий Swagger и дополнительные пакеты, с целью достижения автоматического документирования своих API, с чем успешно справились. Был предложен ряд пакетов, которые можно использовать для решения этой задачи как на Express.js (swagger-express-generate, swagger-ui-express), так и на Gin (swag). Читатель может обратиться к исходному коду и основываясь на данных примерах реализовать документирование API на своих сервисах. Используя инструментарий Swagger можно значительно ускорить процесс создания документации API сервисов, не нагромождая при этом код лишними параметрами спецификации OpenAPI. Сервис NEJ Сервис GG Controller Service Repository Шаблон для работы с swagger-express-generate  Software Engineer