Хочешь сделать что-то полезное и рабочее — сделай его так, чтобы другие люди могли этим полноценно пользоваться, нормально это ревьювить, да и вообще вспоминать тебя добрым словом, а не темной стороной своего словарного запаса.
Для этого, кроме того, чтобы просто хорошо делать свою работу, писать правильный код, не бояться использовать современные технологии и в целом не тупить, надо обязательно обращать внимание на две штуки — документация и API. Без них человеку будет трудно понять, с чем вообще он имеет дело, как оно всё работает и что лучше не трогать вообще никогда. Конечно, можно гуглить, что обозначает та или иная спецификация, можно проверять в бою, чего и как (а потом так же бодро откатываться на предыдущую рабочую версию), но лучше, когда человеку дали подробную документацию.
Так вот, о чем я сегодня. В этом посте я расскажу, почему мы в RBK.money используем Swagger, как он помогает нам в работе и какие у него есть косяки.
Итак, Swagger aka OpenAPI (https://swagger.io/). Swagger хорош тем, что он подразумевает сразу кучу полезных плюшек, вот смотрите:
- типизация переменных
- описание методов
- удобная схема ссылок
- не привязан к какому-то конкретному языку
- да и вообще штука классная, всё, что нам надо, вроде бы, есть.
Схема описывается лаконичным итоговым YAML или JSON-файлом, её легко провалидировать, а интерфейсы можно оперативно генерировать для любого языка. Описать интерфейс на Swagger тоже можно быстро. Тут как — в принципе, особых альтернатив и нету. Конечно, можно вспомнить xml, но лично мне он представляется какой-то неудобной древностью чисто с эстетической точки зрения. Мне это на самом деле кажется важным, потому что я пытаюсь относиться к коду как товарищ Туполев к самолетам:
Хорошо летать могут только красивые самолеты
Да, тут можно похоливарить насчет точности цитаты, да и вообще вспомнить Марселя Дассо и его «un bel avion est un avion qui vole bien», но мы пока не про это. Надеюсь, суть я всё же передал. Так вот. В моём случае, в Sublime Text то, что мы делаем, должно выглядеть красиво. Если это спецификация, то и она тоже. К xml этот тезис, увы, не относится.
А вот YAML — там нет мусора, там только то, что ты написал.
Спецификация Swagger занятная ещё и тем, что можно нормально делать description, definitions. И таким макаром получается, что сам протокол является интерактивной документацией. В арсенале масса классных штук, которые позволяют сделать из YAML вполне приличную вещь. Всё, что мне требуется для её нормальной поддержки — чуток подредактировать спеки в YAML, и всё, у меня готовая документация.
Пример интерактивной документации, построенной на спеке с использованием скриптов ReDoc используется нами на нашем портале разработчика: https://developer.rbk.money/api/.
Ещё о плюсах
Весь протокол виден и описан, вы знаете, какие тут есть типы, если надо проверить чего по степени безопасности — можно спокойно зайти в реализацию протокола в коде и понять, что (как минимум) отвалидированы все типы, которые к вам приходят. Это уже круто, потому что это достаточная степень защиты — набор входящих данных в управляющую команду известен, и проконтролировать соответствие этого набора схеме легко. Оговорюсь сразу, что это не даёт полной гарантии безопасности (спойлер — вообще ничего не дает), но перекрывает сразу огромную кучу потенциальных дырищ.
Ревьювится подобный протокол тоже быстро. На новую сущность добавляется какой-то definition, например, чарджбэк. И тебе не надо муторно ревьювить портянку на несколько метров — смотришь, что добавился новый тип, понимаешь, что именно он делает, это даёт возможность автоматизировать тесты и безопасность. Потому что чарджбэк в принципе по сути своей — это очень сложный бизнес-процесс. И очень тяжёлый. Но тут он уместился в 6 файлов и 224 строчки. Прелесть в том, что этого с головой хватает, чтобы точно понять, какие данные будут тут ходить между микросервисами, описаны все возможные ошибки. В общем, ребята, это реально удобно.
Дебажить — тоже одно удовольствие. Swagger выбрали еще и потому, чтобы можно было быстро зайти из браузера, посмотреть реквесты и пейлоады. Да, конечно, можно было пойти и сделать веб-сокет и усердно гонять там кучу данных, но я не фанат такого — так обычно свой протокол, и без того дичайший, так ещё и бинарный чаще всего, и нормально продебажить это и не захотеть в процессе взять отпуск (или больничный) довольно сложно. Да ещё и приходится в такой схеме всё дико секьюрить, а я хочу открытости и прозрачности. Чтобы можно было резво дернуть curl-ом из консоли и посмотреть, как там дела вообще.
Типов данных хватает с запасом, у нас пока за всё время не было ситуаций, чтобы нам не хватило именно типов данных.
И вот ещё что. Собрал ты распределённую команду, замокал всё, кто-то пишет клиент, кто-то — сервер, ты вообще пошел писать UX/UI для бекенда. Сам бекенд делать долго, но у нас есть swagger-спека, берем её, генерим по ней мок-сервер — и всё. Можно начинать писать фронтенд ещё до того, как бекендер в принципе допьёт свой кофе и включит уже комп, чтобы начать работать. А ты потом пишешь бекенд, меняешь endpoint и получаешь готовое решение. То есть не только можно распараллелить разработку, но и отвязать зависимости команд. Это вот крутая штука.
Минусы, минусы-то есть?
А куда без них, это отличная штука, но пока не серебряная пуля.
Во-первых, Swagger codegen по факту не работает. Нам пришлось его перепиливать, да так увлеклись, что в итоге свой написали. Теперь можем генерить методы и классы. А так на бумаге всё было зашибись, берёшь спеку, генеришь клиент, генеришь сервер, радуешься жизни. На самом же деле тебе ни клиента, ни сервера. Услышав пару отчаянных матов от разрабов на эту тему, я принял решение писать своё.
Во-вторых, у нас на старте был конфликт вот такого рода. Внутри платформы у нас Thrift. Наружу у нас при этом — Swagger. Я, кстати, до сих пор не могу себе признаться, что точно всё правильно сделали, что хорошо, что не везде сразу Swagger взяли. А так было в два раза больше работы, трансляторы протоколов и прочие радости.
Кстати, почему Thrift — у нас были готовые наработки на rpc и клиент-серверные штуки, которые решали транспортные проблемы. Мы быстро туда прикрутили реализацию Google Dapper, реализацию идеи о том, что в распределённой микросервисной среде надо обязательно уметь трассировать запросы. То есть понимать, по какой цепочке микросервисов эти самые вопросы идут, и где тупят, если тупят. В одном из следующих постов об этом будет подробнее. И вышло, что всё есть внутри, а вот наружу надо делать что-то своё.
А ещё чейнджлог. Тут дико слабая автоматизация чейнджлога. Меняешь какие-то методы, чтобы показать, что раньше в этом методе было одно — а тут теперь другое, так вот, кроме диффов в репозитории такого нет. Поэтому чейнджлог надо писать руками. А раз что-то приходится постоянно делать руками, потому что не получилось автоматизировать — это не будут делать вообще. И оно сейчас немного мешает в работе, я, например, не могу клиентам нормально объяснить на пальцах, в чем у нас разница между API 2.0 и API 3.0 — чейнджлога-то нету.
И примеров нет. Обычно они есть, но тут тебе в генераторе документации приходится писать их самому. Оно не так сложно, но — время.
Итого
В целом мы довольны, но есть нюансы — документация не отражает некоторых вложенных структур, сейчас 3-я спецификация, на которую мы пока не можем мигрировать и живем на второй. Но это наш техдолг. Значит — поборем.
А даже если бы и не нравилось что-то большее — пока сваливать-то некуда. Вдруг подскажете в комментах что-то интересное по теме. Само собой, на какой-то отдельный костыльный самопал я Swagger не променяю, потому что что-то костыльное и своё — оно в итоге ещё хуже, чем что-то средненькое, но стандартное.
И вот почему.
Я в принципе был бы очень рад, если бы все, кто сейчас открывает API, пошли бы в сторону Swagger, смотрите — это коммьюнити, прежде всего. Коммьюнити, которое придет, посмотрит на стандарт, на спецификацию, и это начнет развиваться. Где кому чего не понравится — допилят и сделают лучше. Стандарт тут всегда предпочтительнее.
Потому что стандарт можно доработать. А что-то своё можно начать делать в отдельном углу, а потом забить на это, или вообще — тянуть в разные стороны постоянно.
Но опять же, если вы знаете какую-то полезную альтернативу, которая подойдет для решения таких задач — поделитесь в комментах, пожалуйста.
Взять и оценить можно вот тут.
Ремарка после обсуждения в комментариях. Если начинать с нуля, то стоит сразу закладываться на спецификацию Open API Specification 3.0. Там кардинально больше плюшек, можно сказать, что это практически новый стандарт, сильно отличающийся от 2 версии.
somebody4
chainick
Эрланговый стафф. Историю изменений, в принципе, можно смотреть в нашем форке, он открытый https://github.com/rbkmoney/swagger-codegen/pulls?q=is%3Apr+is%3Aclosed
somebody4
Как я понял, вы используете mustache (i.e. logic-less templates) темплейты? Хватает возможностей?
chainick
Да, полностью. Пока не припомню чтобы в какие-то ограничения упирались