DEV Community

Anna
Anna

Posted on

BFF: Секретное оружие фронтенда в мире микросервисов

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

Именно здесь появляется BFF (Backend For Frontend) - это архитектурный паттерн, основная идея которого - это создание отдельного серверного слоя, который представляет из себя прокси сервер, то есть он занимается отправкой запроса на нужный сервис и преобразует ответ в вид, который необходим фронтенду.

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

В данной статье мы разберем BFF и его тонкости.


Что такое BFF? Основные концепции

Мы уже сделали вывод, что BFF - это персональный backend для нашего frontend.

Основная идея данного паттерна заключается в том, что каждый клиент, будь то веб-приложение, мобильное приложение и тд имеет свой "сервер-компаньон", который:
1) Знает его специфические требования (например, нам необходимо отправлять на мобильное приложение ответ с меньшим кол-вом полей, чем на веб-приложение)
2) Оптимизирует работу с серверной частью приложения
3) Предоставляет специализированный API для конкретного UI

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

Ключевый характеристики BFF:

  • Индивидуальность
    BFF создается для конкретного клиента и "заточен" на:
    1) Особенности отображения данных на клиенте.
    2) Особенности сетевого взаимодействия.
    3) Специфические требования к формату данных.
    4) Оптимальные стратегии кэширования данных.

  • "Тонкий" сетевой слой
    BFF не должно содержать бизнес логики, является крайне важно. Основные функции BFF:
    1) Агрегация данных - получение необходимых данных из разных сервисов в единую модель.
    2) Трансформация данных под клиентские нужны.
    3) Маршрутизация запросов к необходимым сервисам.
    4) Обработка ошибок.

Использование данного паттерна в настоящее время становится частой практикой среди frontend сообщества, это связано стем, что:
1) Микросервисная архитектура все чаще и чаще используется на проектах.
2) Большое разнообразие клиентских устройств.


Архитектура BFF в деталях

Рассмотрим общую схему работы BFF:

Общая схема работы BFF

Как запросы проходят через BFF:
1) Запрос с клиента - frontend отправляет один запрос к BFF.
2) Данные попадают в прослойку и начинается работа BFF архитектуры.
3) Аутентификация - проверка токенов и параметров.
4) Параллельные запросы - обращение к микросервисам, которые необходимы.
5) Агрегация данных - объединение результатов по запросам к микросервисам.
6) Трансформация данных - преобразование данных в необходимый для клиента вид.
7) Ответ на клиент - передача сформированного ответа на сторону frontend.

BFF состоит из нескольких логических компонентов:

  • Маршрутизатор, который определяет, какой обработчик должен выполнить запрос и провалидировать данные.
// Пример маршрутизации с Express.js
app.get('/web/products/:id', productPageHandler);
app.get('/web/user-profile', userProfileHandler);
Enter fullscreen mode Exit fullscreen mode
  • Агрегатор данных (Data aggregator), который управляет параллельными запросами и объединяет их результаты.
class DataAggregator {
    async aggregateProductPageData(productId) {
        const [product, reviews, recommendations, stock] = await Promise.all([
            this.catalogService.getProduct(productId),
            this.reviewService.getReviews(productId),
            this.recommendationService.getSimilar(productId),
            this.inventoryService.getStockInfo(productId)
        ]);

        return { product, reviews, recommendations, stock };
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Трансформеры (Transformers), которые преобразуют данные в формат необходимый клиенту.
class ProductTransformer {
    static transformForWeb(productData) {
        const { product, reviews, recommendations, stock } = productData;

        return {
            productInfo: {
                id: product.id,
                name: product.title,
            },
            reviews: {
                items: reviews.slice(0, 10),
            },
            recommendations: recommendations.map(rec => ({
                id: rec.product_id,
                name: rec.product_name,
            })),
            availability: {
                quantity: stock.quantity,
            }
        };
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Клиенты микросервисов (Service Clients), которые специализируются на работе с каждым микросервисом, они формируют HTTP-запросы, обрабатывают ошибки и timeout.

BFF и Микрофронтенды

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

Когда мы используем BFF совместно с микрофронтендами, то существует несколько подходов:
1) Специализированный BFF для каждого MFE - каждый микрофронтенд имеет собственный BFF, они вместе разрабатывается и деплоятся.
2) Единый BFF с модульной структурой - единый BFF-сервер с четким разделением на модули для каждого MFE.

BFF + микрофрентенды имеют следующие преимущества:

  • Полная независимость.
  • Оптимизированная загрузка данных.
  • Устойчивость к изменениям.
  • Единая точка управления.

Данный подход позволяет работать независимо, ускоряет разработку и повышает надежность приложения. BFF - дает нам контроль над данными и позволяет создавать эффективные приложения.

BFF - это первый шаг к улучшению архитектуры, результат не заставит себя долго ждать.

Время стоить архитектуру, которая работает на вас, а не наоборот.

Top comments (0)