Оригинальная статья является размышления на тему почему документация в мире микросервисов критично необходима и как ее можно создавать и публиковать используя swagger. Пошаговой инструкцией по настройке она точно не является.
Вступление
Несколько месяцев назад один из наших бекенд разработчиков интернов получил задачу — разработать новый простой сервис. Сервис должен был генерировать емайл отчеты о пользовательской активности. В задаче не было ничего сложного и у интерна все получилось. Однако через несколько недель мы захотели включить в отчет более детальную информацию о некоторых конкретных пользователях. Я решил обновить этот сервис самостоятельно. “Просто получи данные из нашего пользовательского сервиса и вставь их в емайл”, — думал тогда я.
На это у меня ушло несколько часов, и даже пришлось подключить двоих других разработчиков только для того, чтобы найти правильные REST endpoints и необходимые мен структуры. “Никогда больше. Должен быть более правильный метод это сделать…”, — крутилось у меня в голове все это время.
Микросервисная архитектура подразумевает набор самостоятельных сервисов, которые общаются друг с другом, а для конечного пользователя выглядит как единая программа. Один из самых популярных протоколов для обмена сообщениями между микросервисами — это REST. Проблема в том, что REST не является само описательным протоколом. Это значит, что клиент должен знать конкретную комбинацию URL, HTTP метода и формата ответа. В некоторых случаях необходимо также знать также формат тела запроса. Обычно реализация REST интерфейса базируется на общих принципах и традициях, принятых в вашей организации. В любом случае, REST endpoints всегда должны быть описаны в одном конкретном документе, доступном для всех остальных разработчиков. О том, как и где хранить, мы поговорим чуть позже, а пока давайте обсудим основы — формат документации.
Swagger
Документацию должно быть легко читать, писать, парсить, генерировать, исправлять, обновлять и прочее. Решение должно быть настолько простым, чтобы даже самые ленивые разработчики им пользовались. После небольшого исследования мы в Ataccama решили использовать Swagger для документирования наших REST APIs.
Swagger — это фреймворк и спецификация для определения REST APIs в формате, дружественном к пользователю и компьютеру (в нашем случае JSON или YAML). Но Swagger — это не просто спецификация. Основная его мощь заключается в дополнительных инструментах. Для Swagger существует огромное количество бесплатных утилит (как официальных, так и написанных сообществом), которые могут сделать жизнь (вашу и ваших коллег) немного более счастливой. Вы можете установить все это на свои собственные сервера и посмотреть, как это работает — например, попробовать работу с браузером документов или Swagger онлайн-редактором.
Как мы это делаем?
Если вы тоже думаете, что Swagger — это здорово, то читайте дальше. Сейчас будет немного подробностей о том, как мы используем его в Ataccama, в таинственном мире микросервисов.
У каждого микросервиса в определенной папке лежит файл со Swagger описанием и хранится это все прямо в git-репозитории. Описания могут быть как сгенерированы при помощи Swagger generator, так и записаны туда вручную. Прелесть заключается в том, что для записи определений используются JSON и YAML форматы. Их легко распарсить, и во время сборки проекта мы можем автоматически проверять соответствие REST endpoints и документации. Несоответствия будут генерировать предупреждения, и тем самым стимулировать разработчика поддерживать документацию в актуальном состоянии.
Хранение документации внутри микросервиса позволяет нам отображать её в любое время прямо из этого микросервиса в процессе работы. Это помогает тестировать и отлаживать REST endpoints в процессе развертывания сервиса на собственной машине. А ещё у Swagger есть инструмент с веб интерфейсом для тестирования REST endpoints.
Поскольку каждый микросервис предоставляет собственную документацию, мы можем настроить специальную задачу для Дженкинса (или любого другого CI сервера), которая сгенерирует полную документацию для всего проекта. Эта задача собирает Swagger файлы из всех микросервисов, производит некоторые минимальные модификации (дедупликация, удаление ненужных атрибутов) и на выходе генерирует единый Swagger файл, содержащий полную актуальную информацию для всего проекта.
Публикация документации.
Централизованное хранение и редактирование документации — это только первый шаг. Следующий — сделать ее доступной для всех разработчиков, тестеров и остальных заинтересованных людей в компании. И Swagger UI — это именно то, что вам для этого понадобится. При помощи небольшой JavaScript библиотеки Swagger UI генерирует HTML элементы для всех ваших REST endpoints, которые далее можно упорядочивать с помощью HTML разметки.
По умолчанию Swagger UI подгружает собственный Swagger файл с примерами. Все остальные API должны быть загружены вручную. Но конфигурация занимает всего несколько секунд.
var swaggerUi = new SwaggerUi({
url: ‘http://example.com/swagger.json',
dom_id: ‘swagger-ui-container’
});
swaggerUi.load();
Теперь у нас есть сгенерированная документация в читабельном виде. Время отправить её на сервер.
Некоторое время назад мы в Ataccama начали использовать Docker, и поэтому подумали, а почему бы не упаковать всю документацию в отдельный докер контейнер, загрузить его в наш частный репозитарий, а потом задеплоить в докер кластер? Дженкинc может это сделать буквально за несколько секунд. Как результат мы всегда имеем обновленную документацию доступную к просмотру через браузер.
Кроме того, использование докера дает нам еще несколько преимуществ:
Каждый разработчик может просто загрузить документацию и запустить её на собственном компьютере всего одной командой.
- У каждого докер образа есть версия, и если вам нужна документация к более старому релизу, просто загрузите другой образ с другим докер тегом.
И это только начало.
Это только общая идея того как мы генерируем документацию для REST endpoints и публикуем ее при помощи докера для наших микросервисов. К сожалению, синхронный REST это не все, что нам надо документировать в этом лабиринте микросервисов. В какой-то момент хочется перейти на более продвинутые системы общения, на асинхронный обмен сообщениями, очереди, подписки на события и прочее.
Несмотря на расхваливание Swaggerа мы все еще не нашли удобного метода документирования асинхронных сообщений. По факту, в Атаккаме мы недовольны нашим текущим решением и все еще пытаемся найти что-нибудь более простое и красивое для описания очередей сообщений и их структур. Если у вас есть идеи как это можно сделать лучше, пишите в комментариях. Любые интересные идеи приветствуются.
Оригинал статьи находится здесь.
Автор Lubos Palisek
Backend software developer in Ataccama. Greedy for new cloud based technologies and ideas.
Ataccama Corporation – международная компания, производитель программного обеспечения, специализирующаяся в области решений по управлению качеством данных, управлению мастер-данными и управления данными предприятия (data governance), решениями которого уже воспользовались более 250 компаний, начиная от предприятий среднего размера и заканчивая международными компаниями из различных отраслей.
Все ваши вопросы и рекомендации с удовольствием переведу автору.
Комментарии (12)
Luchnik22
23.02.2017 15:54Микросервисы могут быть написаны не с использованием REST, а, например, с использованием GraphQL или чего — то внутреннего и тогда swag бесполезен.
Отличным местом для описания общения подходит Wiki, проверено. У этого способа описания API тоже есть свои недостатки. Основной, отсутствие генерации кода, зато можно описать что угодно.kefiiir
23.02.2017 16:32+1может быть что угодно, но поскольку у нас REST почему бы не использовать подходящий для этого инструмент.
Вики это хорошо, даже чуть лучше чем просто текстовый файлик на виндовой шаре, но автоматически проверять соответствие документации и существующих эндпоинтов он не может.
saw_tooth
23.02.2017 16:01+1Ох щас выскажусь, об этом сервисе и опыте использования, он конечно может показаться однобоким, так как я не разворачивал его локально, а пользовался онлайн возможностями, но тем не менее. Задача была простой: во время написания сервиса на Flask, нужно было просто какой нить удобный и документированный «тестер запросов», плюс минимально еописание — что делает тото или иной роут, сам сервис небольшой — 40-50 REST API, теперь по порядку.
1. Уродливая система объявления. Куча обязательных параметров, навроде description и прочего, без которого не заводится скрипт, какая то «местозависимая» система объявления (обязательные параметры не выходило менять местами — на кой черт они тогда именованные?) — но черт, мне нужно всего лишь отправить запрос
2. Ужасный онлайн редактор и вывод трейсбеков. Нельзя ровно ни скопировать ни вставить, ни потом запустить. Приходилось одно и тоже по 5 раз переписывать, понять где ошибка просто невозможно, табы/пробелы не различает не заменяет, короче боль. О автодополнении молчу.
3. Глючный UI JS. Создаем роут, описываем ответы, делаем запрос, если JS вдруг получит не то что ожидал (ну например у вас сервак что-то там запарился) — все, UI умирает, ничего отправить/принять нельзя. В хроме UI не работал СОВСЕМ.
4. Авторизация — да чуваки, в 2016 все пользовались только basic типом, и все, другого не дано. Ни совместную не сделать, ни отличную от того что предлагает сам «швагер», а скажите, как мне передать API ключ для всех запросов остальных? а ни как, сначала запускаешь первый запрос, получаешь ключ, и потом его руками копируешь. А что делать если api_key временный?
5. Генерация. Это совсем отдельная песня, такое чувство что он не знает о существовании каких то правил в языках, по крайней мере в питоне, Пустые роуты я и сам могу написать.
Большего терпеть я не стал, и прекратил работу с данным сервисом. У меня все. Не знаю как сейчас у них дела, но все описанное было правдой на лето 2016 года.kefiiir
23.02.2017 17:55+1Swagger is improving quite fast and few of disadvantages you mentioned are already fixed (e.g. «description» mandatory paramters, UI was improved).
Lubos Palisek
frol
23.02.2017 21:09Я не могу сказать, что Swagger идеален, но мне интересно что же стало его заменой в Вашем случае?
Для моих задач Swagger справляется на 4+. Давайте пройдёмся по вашим пунктам:
- "Уродливая система объявления" — похоже, что все описанные раздражающие вещи уже исправлены. Честно говоря, 40-50 методов руками генерировать и потом поддерживать — это сурово, я вот не знаю как автор поддерживает Swagger описания отдельно от своего кода. Я пришёл к тому, что сервер должен строить swagger.json на основании кода, на эту тему у меня есть демо-сервер — https://github.com/frol/flask-restplus-server-example
- Я не могу сказать, что я ежедневно использовал онлайн редактор, но ни разу он не вылетел у меня за последний год.
- Наверно, тоже исправлено, так как я ежедневно пользуюсь Swagger-UI — полёт нормальный, в том числе в Хроме.
- Базовая поддержка OAuth2 в Swagger-UI была добавлена осенью, а около месяца назад наконец добавили и OAuth2 Password Flow
- Что значит "пустые роуты"? Сейчас Python генерация вполне себе сносная (я даже недавно сделал её ещё более "Pythonic", но релиза не было с лета, это да… я мастер ветку использую — полёт нормальный)
Итого, единственный актуальный "камень в огород" Swagger — это практически отсутствующая поддержка различных способов авторизации (в Swagger-UI они наконец хоть что-то полезное добавили, но в кодогенерациях даже с поддержкой OAuth2 тухло, так что приходится патчить, но я надеюсь найти немного времени и прикрутить поддержку OAuth2 для Python и JS, которыми я активно пользуюсь и сейчас у меня накладываются не самые изящные патчи)
Sergey89
23.02.2017 17:14RESTful сервис можно сделать самодокументируемым. HATEOAS
kefiiir
23.02.2017 17:54+1I wouldn't call HATEOS as documentation. You have to interact with HATEOS service to get information about entities and endpoints. It is more self explanatory technique. Swagger will give you full documentation without need to call the service.
Lubos Palisek
frol
23.02.2017 21:19На мой взгляд, HATEOAS — это ужас ужасный. Из Swagger конфигурации можно получить статический клиент, и после этого взаимодействие сводится к обмену полезными данными, в то время как HATEOAS всё время будет слать кучу информации "на всякий случай". Чтобы был хоть какой-то выигрыш HATEOAS, клиент должен быть динамическим, принимающим какие-то решения в процессе взаимодействия, а если клиент декларативный, то пользы, по-моему, никакой. Мне нравится вот это описание: "А нужен ли мне HATEOAS?"
crazylh
Свагер это хорошо, хипстово, современно. Но жизнь чуточку сложнее — бывают сложные сценарии, когда нужно дергать последовательность ручек, вот отсюда из ответа надо взять ИД и передать сюда итд.
Да и стороннему заказчику такое не отдашь, все равно приходится писать текстовое описание.
kefiiir
С этим не поспоришь и именно поэтому автор пишет, что ищет новое более гибкое и умное решение. Но пока что со своими функциями свагер справляется.
У нас свагер используется в SAAS проекте, поэтому отдавать заказчику ничего не надо. А кроме того там хранится только документация для разработчиков. Для пользовательской используются совсем другие средства и даже другая команда.
frol
В таком случае всё сведётся либо к добавлению упрощённого метода, либо к написанию текста к описанию этих сложных посладовательных методов с подсказками и примерами, ровно так же, как это нужно делать и в классической документации, разве нет?