Елизавета Акманова

Старший аналитик

Всем привет! С вами снова я, Елизавета Акманова, старший аналитик в ГК Юзтех. Сегодня хочу поделиться, почему и как мы с командой discovery перешли на описание API с помощью OpenAPI, и при чём здесь системный дизайн. 

OpenAPI & Swagger

В самом начале хочу разграничить понятия OpenAPI и Swagger. Оба термина взаимозаменяемы, если сильно не придираться. Однако, на текущий момент OpenAPI относится к спецификации формата json/yaml, а Swagger — к семейству инструментов с открытым исходным кодом, которые работают со спецификацией OpenAPI. Swagger представляет собой набор следующих инструментов: 

  • Swagger Editor, в котором мы можем быстро редактировать документацию;

  • Swagger UI, в котором мы можем её отобразить;

  • Swagger Codegen, с помощью которого разработчики могут быстро сгенерировать исходный код из документации.

Вот пример небезызвестного Swagger: 

Если всё то, что находится в headers, после названия версии добавить в адресную строку:

Произойдет открытие OpenAPI, на основании которого сгенерирован Swagger:

В данном случае это формат json, однако, если вам удобнее работать с yaml, его можно легко получить, заменив в адресной строке .json на .yaml:

Произойдет скачивание документа на компьютер:

Этот текстовый документ можно открыть в любом текстовом редакторе: Блокнот, Word, Notepad и другие. В нём содержится описание спецификации OpenAPI для того же самого Swagger, но в формате yaml.

Саму структуру файла можно разделить на несколько логических блоков: 

  1. Метаданные
    Этот блок содержит основную информацию о версии OpenAPI, названии, описании. Это помогает пользователям API понять, что они вообще используют:

  1. Описание серверов
    Далее идёт описание серверов. Этот блок определяет серверы, на которых размещен API. Это может быть несколько серверов для различных сред:

  1. Описание запросов
    Далее самое интересное — сами интерфейсы, запросы. Этот блок описывает пути API и методы, которые они поддерживают. В (скобках) я буду писать номер строки, где это можно найти. В данном примере описан путь (8) /users (9), где поддерживается метод GET (10), позволяющий работать со списком пользователей (11). В качестве ответа (12) мы можем получить статус 200 (13), который содержит как раз список пользователей (14), и ответ (15) содержит в себе json (16) схему (17) из массива (18) сущностей (19) Users (20):


    В данном примере ещё не описаны параметры, headers, тело запроса, дабы сэкономить место. Но OpenAPI так же позволяет эту информацию внести.

И назревает актуальный вопрос: где же искать описание сущности Users? Она находится дальше по спецификации.

  1. Описание схем данных
    Этот блок определяет схемы данных, которые используются в API. В данном случае описана схема User, содержащая три свойства: id, name и email. Эти схемы помогают стандартизировать формат данных, передаваемых и принимаемых API:


    К каждому параметру можно добавить его свойства: минимальное/максимальное значение, паттерн заполнения (например, в виде регулярного выражения), значение по умолчанию, значения из списка (в виде enum) и многое другое. 

Вот так выглядит один из самых удобных редакторов OpenAPI, его можете найти по ссылке:

Однако возникает вопрос: кто должен описывать API с помощью OpenAPI? Разработчики, которые используют генераторы OpenAPI? Или аналитики с помощью ручного привода? На моём пути встречались такие разработчики, для которых было мучительно и больно описывать API, поэтому я считаю, что это доля аналитика. Дальше постараюсь обосновать свою точку зрения, но сначала расскажу, как построен процесс работы в нашей команде.

Процесс взаимодействия аналитиков и разработчиков

 У нас всегда при документировании чего-либо есть 2 стороны: разработчики и аналитики. Подход заключается в следующем: аналитиком разрабатывается спецификация и отдаётся на ревью разработчикам. Все изменения, при необходимости, вносятся легко и быстро. Далее, на основе этой спецификации, разработчики своими силами реализуют исходный код, из исходного кода создается сервис, и всё это отдаётся пользователям как продукт. 

Процесс максимально упрощён, чтобы передать общую концепцию!

Чего мы таким подходом добились и какие проблемы закрыли:

  1. Внутреннее единообразие
    Каждый аналитик в команде до этого работал в разных проектах, имел разный бэкграунд и свой подход к оформлению требований, в том числе к API. Сначала каждый из нас писал требования по-своему, с разным уровнем проработки и детализации. Это приводило к разночтению требований разработчиками и тормозило реализацию. У нас была проблема: кто-то описывал API в табличном виде, кто-то просто кидал JSON как пример запроса/ответа, кто-то не описывал вообще (да, такое тоже было).

  2. Чёткая структура
    Таким образом, мы пришли внутреннему единообразию: у нас всё связано, всё согласовано и появляется чёткая структура, которой мы следуем. 

  3. Удобная документация
    Данный формат является привычным для разработчиков и тестировщиков.

  4. Точка правды для команд
    Такие документы становятся единой точкой правды, на которую можно ориентироваться. 

  5. Параллельная разработка
    Этот пункт касается не только клиента и сервера, но ещё и автотестов.

  6. Генерировать код из спецификации
    До этого я видела примеры, когда генерируется спецификация из кода (об этом мы ещё поговорим), но при текущем подходе процессы меняются местами. Правда, не каждая команда готова генерировать свой исходный код из спецификации, а не писать его руками, но чисто технически такая возможность есть.

Казалось бы, большинство этих пунктов можно закрыть введением определенного шаблона документа, по которому аналитики бы описывали API. Зачем нарушать зоны ответственности и впускать аналитика в описание методов согласно спецификации OpenAPI? Тем более, можно в разы сэкономить время и сделать то же самое через генератор, а не описывать вручную. Но здесь я готова чуть-чуть поспорить. 

Проблемы, связанные с генераторами OpenAPI-спецификаций

Я сталкивалась с реальными случаями на проектах, когда генераторы OpenAPI расстраивали всех участников команды. Каким образом? 

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

Внимание, следующий скриншот основан не на реальном проекте, все совпадения случайны!

Согласно спецификации, у нас есть два обязательных поля: isActive и store. Однако, если раскрыть их описание, будет сказано, что они опциональные. По аналогичному кейсу, от разработчика получили такой комментарий: «У меня сваггер не удалось победить с дефолтными полями, решил просто писать описание». Костыль? Он самый. 

В практике мы также сталкивались с тем, что у нас не добавлялись в query params все параметры, которые начинались с is… (тот же isActive). Это было более критично, чем пример выше, поэтому разработчик сжёг определенное количество ресурсов и добился успеха. 

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

То после внедрения этого подхода стал выглядеть примерно так:  

Такое описание интеграторам отдавать приятнее, так как там собрана исчерпывающая информация про метод. 

И ещё как бонус: может произойти ситуация, когда на проекте используются языки программирования и фреймворки, для которых физически нет генератора OpenAPI-спецификации. Случай достаточно редкий, но имеет место быть. 

Как OpenAPI повлиял на системный дизайн

После того, как мы попробовали описывать API в формате OpenAPI, эта же работа в документации стала похожа на то, будто мы сложные, массивные схемы описываем в excel-таблице. Это не плохо, конкретно в нашем случае это ускорило процесс обновления и согласования API-спецификаций. Изменения стали вноситься быстрее, что позволило нам оперативно реагировать на изменения требований и улучшать систему почти в режиме реального времени.

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

Плюс ко всему, отдавать такой Swagger, описанный аналитиком, команде интеграторов стало гораздо приятнее, улучшилась коммуникация как внутри команды, так и за её пределами. Кроме обычных системных названий и их типов там появилось его описание, примеры данных, ограничения и все остальные бонусы, которые при интеграции должны быть учтены. 

Рекомендации по внедрению документации в формате OpenAPI

Кроме банальных советов из разряда «учите спецификацию» хочу порекомендовать выполнять следующие действия: 

  1. Сотрудничайте с командой разработки
    Есть риск, что разработка не поддержит такой подход, так как это заходит на их зону ответственности, и получится как в том самом анекдоте:


    Постарайтесь аргументированно подойти к этому вопросу и найти в разработчиках поддержку. Определите и установите чёткие роли,  обязанности аналитиков, разработчиков и других заинтересованных сторон, чтобы обеспечить бесперебойный рабочий процесс. Проводите регулярные встречи между аналитиками и разработчиками для обсуждения спецификаций API, устранения неясностей и сбора отзывов.

  2. Внедрите подход API-first
    Это значит, что разработка начинается с проектирования API, а не с написания кода. API становится основой для всей системы. Этот шаг требует изменения мышления, но он приведёт к более структурированному и предсказуемому процессу разработки. 

  3. Внедряйте OpenAPI поэтапно
    Начните с малого: с применения спецификаций OpenAPI к небольшой части проекта или одной конечной точке API. Это позволит вам усовершенствовать свой процесс перед его масштабированием. Используйте обратную связь для итеративного улучшения процесса проектирования API, гарантируя, что он соответствует меняющимся потребностям проекта.

  4. Учите спецификацию
    Тут всё просто: смотрите полный набор функций, который представляет спецификация, и используйте её в необходимом объеме. На текущий момент, здесь можно найти последнюю версию спецификации.

  5. Постоянное улучшение и обратная связь
    Последний, но не менее важный шаг — это постоянное улучшение и сбор обратной связи. Мы должны регулярно собирать отзывы от команды, чтобы понимать, что работает хорошо, а что требует доработки. Это поможет нам адаптировать процесс и инструменты под реальные потребности команды, делая нашу работу еще более эффективной.

Выполнив эти шаги, вы сможете обеспечить беспрепятственное внедрение спецификаций OpenAPI аналитиками вашего проекта, что приведёт к более эффективной и последовательной разработке API.

Комментарии (7)


  1. shmakovaa
    08.08.2024 17:05

    Судя по всему у вас разработчики которые зачем-то борются со Swagger'ом, вместо того чтобы дружить с ним. Ну а вообще тут есть как плюсы, так и минусы

    • При генерации спецификации OpenAPI из кода, это снижает трудозатраты на ее описание, это может быть критически важно на молодом проекте, в котором API очень быстро развивается и часто устаревает

    • Если разработчики сильно уйдут в полиморфизм и наследование в своих DTO, то сгенерированная спецификация выйдет довольно сложная к восприятию, и по ней не получится сгенерировать клиент на половине доступных языков программирования

    Ну и забыли упомянуть один из основных плюсов OpenAPI - современные фреймворки позволяют развернуть на бэкенде веб-сервис с веб-интерфейсом его OpenAPI-спецификации (не важно сгенерированной или заранее прописанной из файла), и за счет этого получить песочницу по тестированию этого бэкенда, без необходимости для разработчиков собственноручно писать веб-интерфейс, а для тестировщиков/аналитиков - использовать Postman или Curl.


    1. UseTech Автор
      08.08.2024 17:05

      Привет! Спасибо за комментарий! Ответ от Елизаветы: Насчет трудозатрат — спорный момент, тут все зависит от уровня квалификации аналитика и его опыта работы с OpenAPI. На первых этапах, действительно, казалось, что внедрение этого процесса увеличивает сроки реализации задачи. Но со временем, когда команда набила руку, всё стало идти гораздо быстрее, и по времени это практически не отличается от написания спецификаций вручную в документации.

      Что касается полиморфизма и наследования — пока такой проблемы не возникало. Спасибо за предупреждение, будем внимательнее к этому моменту.

      А вот про генерацию клиентов — отличное дополнение! Мы как раз используем эту функциональность для создания клиентов и тестирования наших бэкэнд-сервисов, что реально упрощает жизнь.

      В общем, вы в точку попали с комментариями. Спасибо, что поделились!


  1. CrazyElephant_X
    08.08.2024 17:05

    А где вы храните спеки по задачам и общую спеку?


    1. UseTech Автор
      08.08.2024 17:05

      Привет!) Ответ от автора:

      В задачах спецификацию не храним, очень сложно потом синхронизировать ее с общей частью, на моем опыте никто из аналитиков после реализации задачи этого не делал (забывали, не хотели, нет времени и еще 1001 причина). Вместо этого вся документация ведется в базе знаний. В таске описываем верхнеуровнево пункты, которые нужно сделать (создать сущность1, реализовать метод2), а для более детальной информации прикрепляем ссылки на страницы в доке и выделяем цветом дельту, которую нужно реализовать.

      Что касается задач на интеграцию: для клиентов (в нашем случае фронтов) или смежных команд достаточно при таком подходе отдать swagger, там вся исчерпывающая информация, которая им необходима. Для разработки бека к swagger еще прикладываем описание внутренней логики, которая также хранится в базе знаний

      Самих баз знаний 2: swagger (хранится в git) и wiki


      1. CrazyElephant_X
        08.08.2024 17:05

        а в гит кто пушит и мержит, разруливает конфликты?

        Мы просто в процессе перехода на Спек-фирст и есть какие-то пробуксовки)


        1. UseTech Автор
          08.08.2024 17:05

          Привет!) Ответ от автора:

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

          Очень здорово, что переходите на новую модель работы со спецификацией! Процесс непростой, это правда, мы его обкатывали не один месяц, но оно того стоит


          1. CrazyElephant_X
            08.08.2024 17:05

            Спасибо большое, будем дальше пробовать