Comments 40
И только в самом крайнем случае, когда нет других вариантов (например, это внешнее API, которое вы никак не контролируете) приходится немножко править ответ.
Симптомы проблемы
Это симптомы алкоголизма или наркомании у того, кто пишет такое апи. На лечение отправьте.
Итак, какие могут быть пути решения этой проблемы? Что мы как фронтендеры можем сделать на своей стороне, чтобы работать с API приемлемого качества?
шаг 1: требование от человека, который "апи принес", предоставлять следующий раз нормальное апи
шаг 2: если шаг 1 не оказался успешным — обращение к начальству с требованием разобраться
шаг 3: если шаг 2 не оказался успешным, увольняться нафиг
— Как вы тестируете соответствие ответа бэкенд АПИ и его Swagger документации? Каки-либо контракт-тесты используете?
— Как часто валидация ответа по JSON-схеме помогало находит ошибки на проде?
— Валидация синхронная, не было у вас проблем с блокированием event-loop при валидации большого ответа?
– Валидация ответов в продакшене очень редко находит баги, т.к. есть несколько ступеней защиты.
Во-первых, после каждого релиза бэкенда надо снапшотить Swagger-схему и проверять, что новая схема является надмножеством старой (дорелизной) схемы. Таким образом мы можем удостовериться, что релиз бэкенда не имеет ломающих изменений, а если имеет, то мы к ним готовы.
Во-вторых, из Swagger’а можно генерировать Flow-типы и смотреть не ругается ли Flow на ваш код.
– Мы утешаем себя тем, что ajv очень быстрый, плюс у нас куча инстансов ноды, балансер и все такое.
Но если это становится проблемой, то можно отключить (полностью или частично) валидацию в проде, оставить только в престейбле.
При этом фейкер дружит со свагером, и вы можете спокойно поднять моковый сервер, который на основе Swagger-схемы будет генерировать вам фейковые ответы по нужным путям.
улыбнуло предложение :)
Мы используем swagger-codegen для гарантии того, что бэкенд формирует правильный ответ. К сожалению, в openapi 2.0 есть целый класс вещей, которые невозможно реализовать, а фронтенд их очень хочет, так что многие вещи приходится делать нелегально. Например, сущность или массив в query параметре.
Кое-что было поправлено в openapi 3.0, но с ним своя беда. Во-первых, отвратительная поддержка тулзами. Тот же openapi-codegen хотя формально и поддерживает новую спеку, ужасно забагован и для продакшена пока не годится. Во-вторых, openapi 3.0 по формату очень не похож на openapi 2.0. Это может и не страшно для маленьких api, но у нас есть спеки по ~12 тысяч строк, которые грамотно отконвертить тоже будет непросто.
Так что у нас в основном проблема именно с фронтом — было бы приятно, если бы фронт не мог отправить неправильный запрос. Нет ли у кого опыта привязывания валидатора запросов на фронте? Пусть не для прода, это как раз интереснее в момент изолированной разработки фронта.
Какие библиотеки и фреймворки вы порекомендуете использовать для реализации подхода и что придется кодить самим?
Какие-то очевидные вещи описаны. Начал делать веб-приложение с нуля год назад. Серверная часть уже существовала лет 15. Сделал прокси как раз для этих очевидных вещей типа агрегации запросов и т.д. Прокси на .net. Свагером генерю сразу клиента на тайпскрипте. Детский сад.
- извращается с регистром полей в ответе (можно не любить конкретно underscored_case, например, но правила есть правила, единообразие важнее творческого самовыражения и личного мнения! в конце концов, командная работа же!);
- извращается с форматом возвращаемого результата (массив, объект или null как результат ответа на один и тот же запрос, который возвращает список — серьезно? как такого на работу взяли?);
- не пишет документацию по своим API (как минимум: имя, тип, текстовое описание каждого параметра запроса и поля в ответе + пример реального запроса и реального ответа на такой запрос).
То есть бэкэндеры у вас пишут как Б-г на душу положит, а фронтэндерам, чтобы как-то интегрировать в клиентскую часть это «творчество», приходится писать целую обертку (BFF), которая более или менее скрывает за собой всю убогость, несогласованность и противоречивость бэка? Я правильно понял?
Команда, пишущая бэк, полностью оторвана от команды, пишущей фронт? Почему бэкэнд сразу не пишется так, чтобы фронтэндерам не было больно при интеграции?
1. BFF позволяет при необходимости менять бэк, не трогая при этом фронт. Бывает удобнее и надёжнее, чем на каждый чих просить фронтендеров делать соответствующие изменения.
2. Если у компании несколько проектов, то новые проекты могут использовать существующие сервисы на бэке, и шарить их с другими проектами. Тут уже так просто бэком не покомандуешь.
То, что вы описали — это вполне разумные причины использования BFF, но в статье же предлагается использовать BFF для того чтобы вот такие какашки:
53 | feed_shoffed_id
54 | fesh
55 | filter-currency
56 | showVendors
Превращать во что-то вменяемое. Вы тоже считаете, что для исполнения в команде бекенда базовых правил культуры и вежливости надо применять BFF, а не административные методы?
Это примерно как если некий человек постоянно матерится на митингах, рассказывает как мам коллег на свидание водил и т.п. вещи, а в качестве решения — давайте приобретем такой девайс, который при произнесении данным человеком определенных ключевых фраз будет пищалку включать, чтоб не слышно было.
но в статье же предлагается использовать BFF для того чтобы вот такие какашки: Превращать во что-то вменяемое.
С такого ракурса использование BFF действительно выглядит избыточно. Либо как жест отчаяния, когда достучаться не получается, а делать надо.
В высоконагруженных системах часто выгоднее отдать данные быстро и компактно, нежели медленно и удобно для конкретного приложения. Поэтому бекенды вольны в выборе формата. А фронтенд подстраивается и собирает как ему нужно.
Второй момент в том, что требования к фронтендам меняются значительно чаще, их проще масшабировать и стоимость ошибки ниже. Поэтому трогать бэкенды лучше в последнюю очередь.
В высоконагруженных системах часто выгоднее отдать данные быстро и компактно, нежели медленно и удобно для конкретного приложения.
И как компактность связана с тем, что в одном месте feed_shoffed_id, а в другом — filter-currency?
Поэтому бекенды вольны в выборе формата.
Конечно же свободен! Только в данном случае никакого формата нет, есть куча говна, которое бекенд вывалил под дверью у фронтенда. И если я под своей дверью вижу кучу говна, то:
- я ожидаю услышать объяснения, четкие и понятные — кто и почему навалил
- я ожидаю услышать извинения
- я уж точно не ожидаю, что предполагается, будто я его стану убирать. Кто намусорил — тот пусть за собой и прибирает.
Если же человек профнепригоден и не способен выполнять работу бекендщика — пусть увольняется нафиг.
Почему пользователь в самом низу на картинке BFF?!) Картинка аж давит)
Переверните пирамидку
Какие проблемы решены?
- фрондендеры имеют API, над которым у них есть контроль
- появилась в каком-то смысле «схема» API, по которой можно валидировать запросы и ответы
- swagger-файл можно в некотором смысле считать документацией
- утверждается, что ушла зависимость от бэкенда, когда там что-то меняется. В это не верю, простите: если бэкенд сменит формат ответа, все равно ваш фасад на ноде переписывать под этот новый формат.
- появилась возможность мокать серверный ответ, собирать ответ несколько API в один ответ фасада, агрегировать данные, играться с форматом ответа сервера
Какие проблемы остались нерешенными:
- бэкенд все ещё творит в апи все, что хочет, и не задумывается над тем, в каком виде они отдают данные и в каком виде эти данные вообще нужны клиенту
- процесс дебага усложнился — вместо того, чтобы посмотреть в серверном коде, почему отдаются неверные данные, теперь сначала нужно заглянуть в фасад — не там ли проблема?
- появилась куча ручной работы — каждый новый серверный API необходимо дублировать
- обработка исключений теперь тоже дублируется: отказать может как сервер, так и фасад
- огромный недокументированный серверный API превратился в два огромных недокументированных API (добавился API фасада)
- появился дополнительный overhead на обработку данных в фасаде, а значит дополнительные сервера, процессорное время etc.
- добавление кеширующего слоя в фасаде, который не контролируется сервером, может привести к неожиданным багам, связанным с использованием устаревших данных
Что ещё забыл?
Я понимаю, что в ситуации, когда уже написано огромное количество различных API, и все они без нормальной документации, представленное решение кажется отличным выходом. Не садиться же в конце концов и не переписывать всё заново, не писать документацию к коду, который уже никто не помнит как вообще работает.
Но можно хотя бы сделать шаг в правильном направлении! У нас в компании ситуация была похожей ещё три-четыре года назад (с единственным исключением: у нас с самого начала был типизированный протокол, общий и для клиентов, и для сервера, в котором хотя бы поля были более-менее откомментированы). И тоже было огромное количество легаси, о котором знали буквально три старожила компании. Мы начали с того, что выделили отдельную команду, которая занималась тем, что проектировала API, описывала в документации сценарии его использования, обсуждала протокол как с серверными, так и с клиентскими разработчиками, и только когда все задействованные стороны согласны с проектом API и сопровождающей документацией — тогда изменения в протокол ехали в мастер и становились доступны как серверу, так и клиентам.
Несмотря на кажущуюся бюрократичность процессса, это окупилось сторицей. Любой разработчик, даже новичок, может начать работу над фичей, потому что все клиент-серверное взаимодействие описано в отличной документации, со скриншотами, примерами сообщений и так далее.
Остается только маленький нюанс.
Почему-то яндекс маркет при всем при этом успешно теряет настройки фильтрации после показа всех фильтров и никак не контролирует статус отложенности для текущего товара, хотя после перехода на полный список видно, что все вроде помнит.
Раньше такой фигни не было.
"Этот код выглядит ужасно. Потому что он ужасен. Но нам все равно нужно это сделать. У нас выбор: делать это на сервере или на клиенте. Я выбираю сервер." — глубокая фраза.)))
Бэкенд для фронтенда, или Как в Яндекс.Маркете создают API без костылей