Мобильное приложение делает 5–10 последовательных HTTP-запросов для загрузки одной страницы. На мобильной сети каждый round trip добавляет 200–500 мс — суммарно до 2–3 секунд. Типичный сценарий: /users/{id}, /orders?userId={id}&limit=3, /notifications/unread, /recommendations?userId={id}, /loyalty/points/{id}. Клиент должен сам дождаться всех ответов и выполнить трансформацию. Это не только медленно, но и потребляет лишний трафик: загрузка ненужных полей (например, полный адрес при просмотре корзины) увеличивает объём передаваемых данных на 30–50%. Экономия на трафике и инфраструктуре может достигать 40% после внедрения BFF. Мы предлагаем внедрить промежуточный слой Backend for Frontend (BFF).
BFF — это отдельный бэкенд-сервис, создаваемый под конкретный тип клиента (веб, мобильное приложение, Smart TV). Он принимает один запрос от клиента, параллельно обращается к необходимым микросервисам, агрегирует данные, отсекает лишнее и возвращает результат в формате, оптимальном для данного клиента. Концепция подробно описана в статье Мартина Фаулера Backend for frontend.
Какие проблемы решает BFF?
- N+1 запрос и задержки. Типичная картина: 5–10 последовательных вызовов для одной страницы. BFF сокращает это до одного вызова, выполняя параллельные запросы к сервисам. Экономия времени — до 80% round trips.
- Избыточные данные. Микросервис отдаёт поля, не нужные клиенту (например, адрес при просмотре корзины). BFF отсекает лишнее, снижая объём передаваемых данных на 30–50%.
- Сложная аутентификация. JWT, refresh token, httpOnly cookie — BFF управляет сессиями централизованно, не раскрывая доступ к сервисам из клиента.
- Частичные сбои. Если один сервис недоступен, BFF может вернуть частичный ответ (null для упавшего фрагмента) вместо 500 ошибки.
- Кеширование общих данных. Размещение BFF между клиентом и сервисами позволяет кешировать агрегированные ответы (например, рекомендации), снижая нагрузку на микросервисы на 40%.
Как мы реализуем BFF: стек и примеры
На практике BFF удобно строить на Node.js с Express или Apollo Server (GraphQL). В проектах мы используем Node.js, TypeScript, Express или Apollo Server, Redis для кеширования (ioredis), axios для HTTP-запросов.
Пример для мобильного приложения
Требуется один эндпоинт /mobile/dashboard, возвращающий профиль, последние заказы, уведомления и баллы лояльности.
// mobile-bff/routes/dashboard.ts
router.get('/mobile/dashboard', authenticate, async (req, res) => {
const userId = req.user.id;
const [userResult, ordersResult, notificationsResult, loyaltyResult] =
await Promise.allSettled([
userService.get(`/users/${userId}`),
orderService.get(`/orders?customerId=${userId}&limit=3&fields=id,status,total,createdAt`),
notificationService.get(`/notifications/${userId}/unread-count`),
loyaltyService.get(`/loyalty/${userId}/summary`)
]);
const response = {
user: userResult.status === 'fulfilled' ? {
id: userResult.value.data.id,
name: userResult.value.data.displayName,
avatar: userResult.value.data.avatarUrl
} : null,
recentOrders: ordersResult.status === 'fulfilled'
? ordersResult.value.data.items.map(transformOrderForMobile)
: [],
unreadCount: notificationsResult.status === 'fulfilled'
? notificationsResult.value.data.count
: 0,
loyalty: loyaltyResult.status === 'fulfilled' ? {
points: loyaltyResult.value.data.balance,
tier: loyaltyResult.value.data.tier
} : null
};
res.json(response);
});
Пример для веб-клиента
Веб-клиенту требуются те же данные, но с полным профилем, большим списком заказов и аналитикой.
// web-bff/routes/dashboard.ts
router.get('/web/dashboard', authenticate, async (req, res) => {
const userId = req.user.id;
const [user, orders, stats, notifications] = await Promise.allSettled([
userService.get(`/users/${userId}`),
orderService.get(`/orders?customerId=${userId}&limit=10`),
analyticsService.get(`/analytics/user/${userId}/stats`),
notificationService.get(`/notifications/${userId}?limit=5&unread=true`)
]);
res.json({
user: user.status === 'fulfilled' ? user.value.data : null,
orders: orders.status === 'fulfilled' ? orders.value.data : { items: [], total: 0 },
analytics: stats.status === 'fulfilled' ? stats.value.data : null,
notifications: notifications.status === 'fulfilled' ? notifications.value.data : []
});
});
Развернуть пример для GraphQL BFF
// web-bff/graphql/schema.ts
const typeDefs = gql`
type Query {
dashboard: Dashboard!
order(id: ID!): Order
}
type Dashboard {
user: User!
recentOrders: [Order!]!
stats: UserStats!
}
`;
const resolvers = {
Query: {
dashboard: async (_, __, { userId }) => {
const [user, orders, stats] = await Promise.all([
userService.getUser(userId),
orderService.getRecentOrders(userId),
analyticsService.getUserStats(userId)
]);
return { user, recentOrders: orders, stats };
}
}
};
Как реализовать авторизацию и кеширование в BFF?
BFF — естественное место для централизованной авторизации и кеширования. JWT-токен проверяется на уровне BFF, refresh token хранится в httpOnly cookie (для веб-клиента), а кеш в Redis ускоряет ответы для редко меняющихся данных.
// authorization middleware
router.post('/auth/refresh', async (req, res) => {
const refreshToken = req.cookies.refresh_token;
if (!refreshToken) return res.status(401).json({ error: 'No token' });
const tokens = await authService.refreshTokens(refreshToken);
res.cookie('refresh_token', tokens.refreshToken, {
httpOnly: true, secure: true, sameSite: 'strict',
maxAge: 30 * 24 * 60 * 60 * 1000
});
res.json({ accessToken: tokens.accessToken });
});
// caching with Redis
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);
async function getCachedOrFetch<T>(key: string, ttl: number, fetcher: () => Promise<T>): Promise<T> {
const cached = await redis.get(key);
if (cached) return JSON.parse(cached);
const data = await fetcher();
await redis.setex(key, ttl, JSON.stringify(data));
return data;
}
Выбор между GraphQL и REST для BFF
Если клиент — React-приложение с Apollo Client, BFF может экспортировать GraphQL-схему. Это даёт клиенту возможность запрашивать ровно те поля, которые нужны, без дублирования эндпоинтов. GraphQL BFF особенно удобен, когда требования к данным часто меняются: клиент сам контролирует выборку. Однако для простых мобильных приложений с фиксированными экранами REST BFF часто оказывается эффективнее из-за меньшей сложности.
Что входит в работу
- Аудит текущей архитектуры и выявление частых round trips.
- Проектирование BFF-слоя для каждого клиента (REST или GraphQL).
- Разработка API с агрегацией данных и трансформацией.
- Внедрение авторизации (JWT, session-based).
- Кеширование с Redis или in-memory.
- Обработка ошибок и partial failures (Promise.allSettled).
- Документация (OpenAPI или GraphQL SDL).
- Тестирование и нагрузочное тестирование.
- Деплой (Docker, Nginx, Vercel, AWS Lambda).
Сроки реализации
| Тип BFF | Срок |
|---|---|
| REST BFF для 1 клиента (3–5 эндпоинтов) | 1–2 недели |
| GraphQL BFF + авторизация + кеширование | 2–3 недели |
| BFF для 2–3 клиентов с общей библиотекой | 3–4 недели |
Процесс работы
- Аналитика — изучаем схему запросов и выделяем узкие места.
- Проектирование — определяем набор агрегируемых эндпоинтов и стек.
- Реализация — пишем BFF-слой, кеширование, авторизацию.
- Тестирование — модульные, интеграционные, performance-тесты.
- Деплой — развёртывание и настройка мониторинга.
Типичные ошибки при внедрении BFF
- Дублирование логики — каждый BFF дублирует трансформации. Решение: вынести общие функции в shared library.
- Монолитный BFF — один BFF для всех клиентов приводит к тем же проблемам, что и единый API. Каждый клиент — отдельный BFF.
- Игнорирование partial failures — если один сервис не отвечает, BFF не должен падать. Используйте
Promise.allSettled. - Отсутствие кеширования — без кеша каждый запрос долетает до сервисов, увеличивая нагрузку и время ответа.
Почему BFF превосходит единый API?
Без BFF клиент вынужден самостоятельно агрегировать данные, что ведёт к избыточным запросам и усложнению клиентской логики. BFF берёт на себя оркестрацию: один запрос от клиента → параллельный опрос микросервисов → агрегация → трансформация → ответ. Это ускоряет загрузку, снижает трафик и упрощает поддержку.
Наш опыт
Мы внедрили BFF для крупного e-commerce проекта. Результаты:
| Параметр | Без BFF | С BFF |
|---|---|---|
| Количество запросов на экран | 7 | 1 |
| Время загрузки | 3.2 с | 0.8 с |
| Трафик на экран | 150 КБ | 80 КБ |
| Нагрузка на сервисы | 100% | ~60% |
Опыт наших инженеров — 8+ лет в микросервисной архитектуре. Закажите разработку BFF под ключ и получите гарантию на время ответа и отказоустойчивость. Свяжитесь с нами для бесплатной консультации — оценим ваш проект за 1–2 дня. Закажите разработку BFF и получите оптимизацию под ваш клиент.







