Понимание шаблона Backend for Frontend (BFF): простое руководство

Понимание шаблона Backend for Frontend (BFF): простое руководство

В архитектуре микросервисов наши системы разбиты на десятки небольших специализированных сервисов, таких как сервис пользователей, сервис заказов и сервис продуктов.

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

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

Именно эту проблему решает Шаблон Backend for Frontend (BFF). В этом руководстве мы объясним этот шаблон простыми словами, рассмотрим аналогию из реальной жизни, сравним его со стандартным шлюзом API и рассмотрим практическую реализацию кода.


Реальная аналогия: меню ресторана

Представьте себе ресторан, в котором обслуживают три совершенно разных типа посетителей:

  1. Кулинарный критик, которому нужно полное дегустационное меню из 5 блюд с подробным списком ингредиентов.
  2. Занятой пассажир, который хочет быстро перекусить в заранее упакованном виде в поезде.
  3. Ребенок, которому нужна простая детская еда с небольшими порциями и без острых ингредиентов.

Если бы в ресторане было только одно-единственное меню, в котором подробно перечислялись бы все три варианта, это было бы ошеломляюще. Пассажиры будут тратить время на чтение рецептов из пяти блюд, а родителям ребенка будет сложно найти простые варианты еды.

Вместо этого ресторан печатает три индивидуальных меню: дегустационное меню, экспресс-меню с собой и детское меню.

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

В этом сценарии:

  • Кухня представляет ваши микросервисы (Пользователь, Каталог, Оплата).
  • Пользовательские меню – это ваши лучшие друзья (лучшие друзья в Интернете, лучшие друзья на мобильных устройствах, лучшие друзья на просмотре).
  • Закусочные — это ваши интерфейсы (браузер на рабочем столе, мобильное приложение, умные часы).

Проблема: универсальный API

Когда микросервисы впервые стали популярными, многие команды создали единый общий API-шлюз для обслуживания всех клиентов внешнего интерфейса:

Схема архитектуры Backend for Frontend (BFF), сравнивающая веб- и мобильные потоки

Хотя единая точка входа — это здорово, общий API создает несколько узких мест масштабирования:

  • Раздутие полезной нагрузки для мобильных устройств. Для настольного веб-приложения требуется история заказов пользователя, платежный адрес, изображение профиля и баллы лояльности. В мобильном приложении должно отображаться только «Последний заказ: отправлен». Благодаря общему API мобильное приложение загружает всю полезную нагрузку профиля, тратя ценные данные и замедляя время загрузки.
  • Узкие места API. Единственная команда становится узким местом для общего шлюза. Если команда iOS хочет изменить небольшое поле макета, ей придется дождаться, пока команда общего шлюза развернет новую версию, что замедляет циклы разработки.
  • Различные потребности в безопасности. Веб-браузеру могут потребоваться сеансы на основе файлов cookie для предотвращения межсайтового выполнения сценариев (XSS), тогда как мобильное приложение предпочитает заголовки OAuth на основе токенов. Обработка обоих на одном сервере создает сложный и беспорядочный код.

Решение: шаблон BFF

Вместо создания одного гигантского шлюза для всех устройств Шаблон BFF предлагает создать один выделенный внутренний сервер для каждого внешнего приложения.

У вас будет:

  • Web BFF: обрабатывает запросы из браузера настольного компьютера. Он объединяет полные профили, каталоги продуктов и подробную информацию о оформлении заказа.
  • Мобильный лучший друг: обрабатывает запросы от приложений iOS и Android. Он агрегирует данные, отфильтровывает ненужные поля и сжимает окончательный ответ для обеспечения высокой производительности.

API-шлюз и BFF: в чем разница?

Эти два шаблона часто путают, поскольку оба они находятся между клиентом и микросервисами. Вот различие:

Особенность Общий шлюз API Бэкэнд для фронтенда (BFF)
Количество шлюзов Обычно один для всей системы. Несколько (по одному для каждого типа клиентского устройства).
Ответственность Высокоуровневая маршрутизация, ограничение скорости и глобальная безопасность. Агрегирование данных и адаптация полезных данных для конкретного интерфейса.
Право собственности Управляется специальной командой по бэкэнду/платформенной инфраструктуре. Управляется командой внешнего интерфейса, которая создает соответствующее приложение.
Кастомизация Низкий. Изменения коснутся всех клиентов. Высокий. Изменения коснутся только одного клиентского приложения.

Практическая реализация (Node.js/Express)

Чтобы понять, как это работает на практике, напишем простой пример Node.js.

Представьте, что у нас есть два микросервиса, работающие внутри:

  • Служба пользователя (возвращает основную информацию профиля пользователя)
  • Сервис заказов (возвращает список заказов с полной информацией)

Мы хотим создать Веб-лучший друг и Мобильный лучший друг, чтобы по-разному обслуживать наш сайт для ПК и мобильное приложение.

1. Макет общих микросервисов

Во-первых, вот макеты данных для двух наших базовых микросервисов:

// Internal User Service Response
const userProfile = {
    id: 42,
    username: "dev_coder",
    email: "coder@ghaznix.com",
    avatarUrl: "https://ghaznix.com/avatars/42.png",
    preferences: { theme: "light", newsletter: true }
};

// Internal Order Service Response
const orderHistory = [
    { id: "ORD-99", date: "2026-06-25", items: ["Laptop", "Mouse"], status: "Shipped", tax: 15.00, total: 1215.00 },
    { id: "ORD-88", date: "2026-05-12", items: ["Keyboard"], status: "Delivered", tax: 5.00, total: 105.00 }
];

2. Web BFF (возвращает полную подробную полезную нагрузку)

Web BFF объединяет все поля, поскольку на экране рабочего стола достаточно места для их отображения:

const express = require('express');
const webBff = express();

webBff.get('/dashboard', (req, res) => {
    // Web needs everything: profile + full order details + settings
    const responsePayload = {
        user: {
            username: userProfile.username,
            email: userProfile.email,
            avatar: userProfile.avatarUrl,
            theme: userProfile.preferences.theme
        },
        orders: orderHistory // Send all order details, taxes, and items
    };
    
    res.json(responsePayload);
});

webBff.listen(3001, () => console.log('Web BFF running on port 3001'));

3. Mobile BFF (минимизированная агрегированная полезная нагрузка)

Mobile BFF отфильтровывает ненужные поля (например, адрес электронной почты, настройки и налоги) и объединяет элементы заказа для экономии трафика:

const express = require('express');
const mobileBff = express();

mobileBff.get('/dashboard', (req, res) => {
    // Mobile only wants: username, avatar, and summary of the latest order
    const latestOrder = orderHistory[0];
    
    const responsePayload = {
        user: {
            username: userProfile.username,
            avatar: userProfile.avatarUrl
        },
        latestOrderStatus: {
            orderId: latestOrder.id,
            status: latestOrder.status,
            date: latestOrder.date,
            itemCount: latestOrder.items.length // Send count instead of array list
        }
    };
    
    res.json(responsePayload);
});

mobileBff.listen(3002, () => console.log('Mobile BFF running on port 3002'));

Сравнение размеров полезной нагрузки

  • Размер ответа Web BFF: содержит вложенную конфигурацию, настройки, полный список заказов, налоги, товары и т. д. (около 400 байт).
  • Размер ответа Mobile BFF: содержит только 6 пар ключ-значение, представляющих самое необходимое. (Приблизительно 120 байт — уменьшение размера сети на 70 %!).

Плюсы и минусы шаблона BFF

Несмотря на свою высокую эффективность, шаблон BFF имеет свои недостатки:

Преимущество (Про) Недостаток (Против)
Оптимизированная производительность клиента: клиенты загружают только те данные, которые им нужны, что снижает расход заряда батареи и использование памяти. Дублирование кода. Возможно, вам придется написать аналогичную логику получения данных в нескольких базах кода BFF.
Ускоренные циклы выпуска. Команда мобильного интерфейса может обновлять свой сервер BFF без необходимости координации с веб-разработчиками. Увеличено количество серверов. Вместо управления одним шлюзом API теперь необходимо развертывать и управлять несколькими службами BFF.
Упрощенный внешний код: клиенту не нужно обрабатывать сложную логику сортировки, фильтрации или слияния; он просто отображает полученный JSON. Управление безопасностью. Сертификация SSL/TLS, правила ограничения скорости и брандмауэры должны управляться на нескольких шлюзах.

Заключение

Шаблон Backend for Frontend (BFF) — это мощная архитектура для систем, которые обслуживают несколько типов клиентов, таких как Интернет, мобильные устройства и устройства IoT. Создавая индивидуальные шлюзы для каждого конкретного интерфейса, вы отделяете разработку клиента, минимизируете размер полезной нагрузки и обеспечиваете более быстрый и отзывчивый пользовательский интерфейс.

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


Узнайте больше о разработке программного обеспечения и серверной части в блоге Ghaznix →