Gymterview
senior

Что такое BFF (Backend for Frontend) и API Gateway?

BFF (Backend for Frontend) и API Gateway — архитектурные паттерны, определяющие, как клиенты взаимодействуют с backend-сервисами в микросервисной архитектуре.

API Gateway — единая точка входа

API Gateway — прокси-сервер, являющийся единственной точкой входа для всех клиентов. Маршрутизирует запросы и предоставляет сквозную функциональность.

Пример
    Web App     Mobile App     Partner API
       \            |            /
        ┌───────────▼───────────┐
        │      API Gateway      │
        │ (routing, auth, rate  │
        │  limiting, logging)   │
        └────┬────┬────┬────────┘
             │    │    │
        ┌────▼┐ ┌─▼──┐ ┌▼────┐
        │User ││Order││Stock│
        │Svc  ││ Svc ││ Svc │
        └─────┘ └────┘ └─────┘

Функции: маршрутизация, аутентификация/авторизация, Rate Limiting, логирование, трансформация запросов, кэширование, Circuit Breaker.

BFF — отдельный API для каждого типа клиента

Для каждого типа клиента (web, mobile, admin) создаётся отдельный backend-сервис, оптимизированный под потребности этого клиента.

Пример
    Web App         Mobile App        Admin Panel
       │                │                  │
  ┌────▼─────┐    ┌─────▼──────┐    ┌─────▼──────┐
  │ Web BFF  │    │ Mobile BFF │    │ Admin BFF  │
  │(подробные│    │(компактные │    │(все данные)│
  │ данные)  │    │ данные)    │    │            │
  └──┬───┬───┘    └──┬───┬─────┘    └──┬───┬─────┘
     │   │           │   │             │   │
     └───┴───────────┴───┴─────────────┴───┘
              Микросервисы (User, Order, Stock)

Сравнение подходов

Характеристика Прямые вызовы API Gateway BFF
Сложность Минимальная Средняя Высокая
Оптимизация под клиента Нет Частичная Полная
Агрегация данных На клиенте Ограниченная Полная
Over-fetching Да Да Нет
Безопасность На каждом сервисе Централизованная На каждом BFF
Примеры реализации

API Gateway на Spring Cloud Gateway:

@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service", r -> r
                .path("/api/users/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .circuitBreaker(cb -> cb
                        .setName("userServiceCB")
                        .setFallbackUri("forward:/fallback/users"))
                    .retry(retry -> retry.setRetries(3)))
                .uri("lb://user-service"))
            .route("order-service", r -> r
                .path("/api/orders/**")
                .filters(f -> f
                    .stripPrefix(1)
                    .requestRateLimiter(rl -> rl
                        .setRateLimiter(redisRateLimiter())
                        .setKeyResolver(userKeyResolver())))
                .uri("lb://order-service"))
            .build();
    }
}

Mobile BFF — один вызов для главного экрана:

@RestController
@RequestMapping("/mobile/api")
@RequiredArgsConstructor
public class MobileBffController {

    private final UserServiceClient userClient;
    private final OrderServiceClient orderClient;
    private final NotificationServiceClient notificationClient;

    @GetMapping("/home")
    public ResponseEntity<MobileHomeResponse> getHomeScreen(
            @AuthenticationPrincipal UserPrincipal principal) {

        CompletableFuture<UserSummary> userFuture =
            CompletableFuture.supplyAsync(() -> userClient.getSummary(principal.getId()));
        CompletableFuture<List<OrderBrief>> ordersFuture =
            CompletableFuture.supplyAsync(() -> orderClient.getRecent(principal.getId(), 5));
        CompletableFuture<Integer> notifCountFuture =
            CompletableFuture.supplyAsync(() -> notificationClient.getUnreadCount(principal.getId()));

        CompletableFuture.allOf(userFuture, ordersFuture, notifCountFuture).join();

        MobileHomeResponse response = new MobileHomeResponse(
            userFuture.join(), ordersFuture.join(), notifCountFuture.join()
        );
        return ResponseEntity.ok(response);
    }
}

Когда что использовать

  • API Gateway (без BFF): все клиенты имеют одинаковые потребности, нужна централизованная маршрутизация.
  • BFF: клиенты имеют существенно разные потребности, нужна агрегация данных из нескольких сервисов.
  • API Gateway + BFF: Gateway для auth/rate limiting/logging, BFF для агрегации и адаптации данных.

Частые ошибки

  • Реализация бизнес-логики в API Gateway — шлюз должен быть «тонким».
  • Единый BFF для всех клиентов — это просто API Gateway, а не BFF.
  • Синхронные вызовы к микросервисам из BFF — используйте CompletableFuture или virtual threads.
  • Отсутствие Circuit Breaker в BFF.

Как используется в 2026

  • Spring Cloud Gateway — стандарт для API Gateway в экосистеме Spring.
  • GraphQL как альтернатива BFF для гибких запросов.
  • BFF + Virtual Threads (Java 21+) — упрощают параллельные вызовы.
  • API Gateway as a Service — Kong, AWS API Gateway, Azure APIM.

На собеседовании: нужно чётко разграничить API Gateway (сквозная функциональность: auth, routing, rate limiting) и BFF (агрегация и адаптация данных под конкретный клиент). Частая ошибка — путать их или считать, что BFF заменяет API Gateway. Они дополняют друг друга.