Die Kernunterschiede zwischen API-Gateways und BFFs verstehen
Ethan Miller
Product Engineer · Leapcell

Einleitung
In der sich entwickelnden Landschaft moderner Softwarearchitekturen, insbesondere mit der weit verbreiteten Einführung von Microservices, ist die Verwaltung des komplexen Dienstleistungsnetzes und die Optimierung der Kommunikation zwischen Frontends und Backends von größter Bedeutung geworden. Zwei Architekturmuster, die in Diskussionen über diese Herausforderung häufig vorkommen, sind API-Gateways und Backend for Frontend (BFF). Obwohl beide scheinbar als Vermittler fungieren, sind ihre Zwecke, Funktionalitäten und beabsichtigten Anwendungsfälle grundlegend unterschiedlich. Ein Missverständnis dieser Unterschiede kann zu suboptimalen Architekturentscheidungen, erhöhter Komplexität und geringerer Entwicklungsgeschwindigkeit führen. Dieser Artikel zielt darauf ab, die grundlegenden Unterschiede zwischen API-Gateways, wie sie von Tools wie Kong verkörpert werden, und dem BFF-Muster zu klären und zu veranschaulichen, warum beide aus unterschiedlichen Gründen in einem gut gestalteten System entscheidend sind.
Analyse der Vermittler
Bevor wir uns mit den Kernunterschieden befassen, sollten wir ein klares Verständnis der beteiligten Schlüsselbegriffe etablieren.
API-Gateway: Ein API-Gateway ist ein Server, der als einziger Einstiegspunkt für eine definierte Reihe von Microservices fungiert. Es aggregiert gemeinsame Funktionalitäten, die von mehreren Clients benötigt werden, und leitet Anfragen an die entsprechenden Backend-Dienste weiter. Betrachten Sie es als den „Verkehrspolizisten“ für Ihre Microservices, der sich übergreifende Anliegen kümmert, bevor Anfragen Ihre einzelnen Dienste überhaupt erreichen.
Backend for Frontend (BFF): Das BFF-Muster beinhaltet die Erstellung eines dedizierten Backend-Dienstes für jede spezifische Frontend-Anwendung oder Benutzererfahrung. Anstelle einer einzigen, monolithischen API, die alle Clients bedient, erhält jedes Frontend (z. B. Web-App, iOS-App, Android-App) sein eigenes, angepasstes Backend. Dieses Backend orchestriert dann Aufrufe an verschiedene nachgelagerte Microservices, transformiert und aggregiert Daten, um den spezifischen Anforderungen seines entsprechenden Frontends gerecht zu werden.
API-Gateway: Die Infrastrukturschicht
Das API-Gateway operiert hauptsächlich auf Infrastrukturebene. Seine Kernaufgaben sind breit gefächert und oft generisch und gelten für alle eingehenden Anfragen, unabhängig vom Client.
Prinzipien:
- Zentralisierte Anfragenverarbeitung: Alle externen Anfragen kommen über das Gateway.
 - Übergreifende Anliegen: Behandelt Authentifizierung, Autorisierung, Ratenbegrenzung, Verkehrsmanagement, Routing, Load Balancing, Caching und Analysen.
 - Serviceerkennung: Findet und leitet Anfragen an die richtigen Microservice-Instanzen weiter.
 - Protokollübersetzung: Kann verschiedene Protokolle konvertieren (z. B. REST zu gRPC).
 
Implementierung (Konzeptionell mit Kong):
Stellen Sie sich vor, Sie haben mehrere Microservices: UserService, ProductService und OrderService. Ohne ein API-Gateway müsste Ihr Frontend die IPs und Ports jedes einzelnen kennen und allgemeine Anliegen manuell behandeln.
Mit Kong würden Sie Routen definieren, die eingehende Anfragen Ihren Diensten zuordnen:
# kong.yml _format_version: "2.1" services: - name: user-service url: http://user-service:8080 routes: - name: user-route paths: - /users strip_path: true - name: product-service url: http://product-service:8081 routes: - name: product-route paths: - /products strip_path: true plugins: - name: jwt # Beispiel: JWT-Authentifizierung global anwenden service: user-service config: claims_to_verify: ["exp"]
In diesem Beispiel kümmert sich Kong um das Routing von /users zu user-service und /products zu product-service. Es kann auch Plugins wie die JWT-Authentifizierung universell auf jeden Dienst oder jede Route anwenden und diese Verantwortung von den einzelnen Microservices abladen.
Anwendungsszenarien:
- Externe Bereitstellung von Microservices: Bietet einen einzigen, sicheren Einstiegspunkt für externe Clients.
 - Verwaltung von API-Versionen: Kann Anfragen an verschiedene Versionen von Diensten weiterleiten.
 - Sicherheitsdurchsetzung: Zentralisierte Authentifizierung, Autorisierung und Bedrohungsschutz.
 - Überwachung und Analysen: Erfasst Metriken zur API-Nutzung und Leistung.
 
BFF: Die Client-spezifische Schicht
Das BFF-Muster hingegen ist ein Entwurfsmuster, das sich auf die Optimierung der Erfahrung für spezifische Clients konzentriert. Es ist clientzentriert, nicht infrastrukturszentriert.
Prinzipien:
- Client-spezifische API: Jedes Frontend erhält eine API, die genau auf seine Bedürfnisse zugeschnitten ist.
 - Datenaggregation und -transformation: Kombiniert Daten aus mehreren nachgelagerten Diensten zu einer einzigen, optimierten Antwort für den Client.
 - Reduzierte Komplexität auf Client-Seite: Lagert Datenmanipulation und Orchestrierung vom Frontend aus.
 - Unabhängige Bereitstellung: Ein BFF kann unabhängig von anderen BFFs und Kern-Microservices weiterentwickelt und bereitgestellt werden.
 
Implementierung (Konzeptionell in Node.js für eine Web-UI):
Betrachten Sie ein Szenario, in dem Ihre Webanwendung das Profil eines Benutzers anzeigen muss, einschließlich seiner letzten Bestellungen und Lieblingsprodukte. Diese Daten stammen von UserService, OrderService und ProductService.
// web-bff/src/index.js const express = require('express'); const axios = require('axios'); const app = express(); const port = 3001; // Gehen Sie davon aus, dass dies interne Microservice-URLs sind, die möglicherweise intern über ein API-Gateway geleitet werden const USER_SERVICE_URL = 'http://user-service:8080'; const ORDER_SERVICE_URL = 'http://order-service:8082'; const PRODUCT_SERVICE_URL = 'http://product-service:8081'; app.get('/api/web/user-dashboard/:userId', async (req, res) => { try { const userId = req.params.userId; // Benutzerdetails abrufen const userRes = await axios.get(`${USER_SERVICE_URL}/users/${userId}`); const userData = userRes.data; // Aktuelle Bestellungen des Benutzers abrufen const ordersRes = await axios.get(`${ORDER_SERVICE_URL}/orders?userId=${userId}&limit=5`); const recentOrders = ordersRes.data; // Lieblingsprodukte des Benutzers abrufen (angenommen, Produkt-IDs befinden sich in Benutzerdaten) const productIds = userData.favoriteProductIds || []; const productPromises = productIds.map(productId => axios.get(`${PRODUCT_SERVICE_URL}/products/${productId}`) ); const productResponses = await Promise.all(productPromises); const favoriteProducts = productResponses.map(response => response.data); // Daten für eine einzelne Web-Client-Ansicht aggregieren und transformieren const dashboardData = { user: { id: userData.id, name: userData.name, email: userData.email, }, recentOrders: recentOrders.map(order => ({ orderId: order.id, totalAmount: order.total, status: order.status })), favoriteProducts: favoriteProducts.map(product => ({ productId: product.id, name: product.name, price: product.price })) }; res.json(dashboardData); } catch (error) { console.error('Fehler beim Abrufen der Benutzer-Dashboard-Daten:', error.message); res.status(500).json({ message: 'Abrufen der Dashboard-Daten fehlgeschlagen' }); } }); app.listen(port, () => { console.log(`Web BFF hört auf http://localhost:${port}`); });
Hier aggregiert der Endpunkt /api/web/user-dashboard/:userId im web-bff Daten aus mehreren Microservices und passt die Antwort speziell für eine Weboberfläche an, was potenziell Boilerplate-Code im Frontend reduziert und Netzwerkanrufe optimiert.
Anwendungsszenarien:
- Mehrere Client-Typen: Wenn Sie erheblich unterschiedliche Client-Anwendungen (z. B. Mobil, Web, Smart-TV) mit unterschiedlichen Datenstrukturen oder Detailgraden benötigen.
 - Komplexe UI-Datenaggregation: Wenn ein einzelner UI-Bildschirm Daten von vielen Backend-Diensten benötigt, was verhindert, dass das Frontend mehrere sequentielle API-Aufrufe tätigt.
 - Evolvierende Frontends: Ermöglicht Frontends, schneller zu iterieren und bereitzustellen, ohne andere Clients oder Kern-Backend-Dienste zu beeinträchtigen.
 - Sicherheit pro Client: Feingranulare Zugriffskontrolle, die auf die spezifischen Berechtigungen jedes Clients zugeschnitten ist.
 
Der grundlegende Unterschied
Der grundlegende Unterschied liegt in ihrem Verantwortungsbereich und ihrer treibenden Kraft.
- 
API-Gateway ist dienstzentriert: Es konzentriert sich darauf, einen stabilen, sicheren und performanten Einstiegspunkt für alle Clients zu bieten, um Ihre Backend-Dienste kollektiv zu nutzen. Seine Anliegen sind meist horizontal (übergreifend) und infrastrukturbezogen. Es kennt oder kümmert sich nicht um die spezifischen Anzeigeanforderungen eines bestimmten Frontends. Sein Ziel ist die effiziente und sichere API-Exposition.
 - 
BFF ist clientzentriert: Es konzentriert sich auf die Optimierung der Interaktion für eine spezifische Frontend-Anwendung. Seine Anliegen sind vertikal (clientspezifisch) und anwendungsbezogen. Es versteht die UI/UX-Anforderungen seines zugehörigen Clients und fungiert als spezialisierter Adapter, der Daten aggregiert und transformiert, um die Komplexität auf Client-Seite und Netzwerkanrufe zu reduzieren.
 
Sie können und sollten oft beides verwenden. Ein API-Gateway könnte vor allen Ihren BFFs (und potenziell anderen direkten Microservices) sitzen und die allererste Ebene gemeinsamer Anliegen wie Authentifizierung und Ratenbegrenzung für die eingehenden Anfragen verwalten. Dann werden die Anfragen an das entsprechende BFF weitergeleitet, das dann Aufrufe an die tieferen Microservices orchestriert.
Fazit
Obwohl sowohl API-Gateways als auch BFFs als wichtige Vermittler in Microservice-Architekturen fungieren, dienen sie unterschiedlichen Zwecken. Das API-Gateway ist Ihre robuste, gemeinsame Infrastrukturschicht, die die gemeinsamen Einstiegspunkte und übergreifenden Anliegen für Ihr gesamtes Ökosystem verwaltet. Das Backend for Frontend ist eine spezialisierte, clientgesteuerte Schicht, die sorgfältig API-Erlebnisse kuratiert, die für einzelne Frontend-Anwendungen optimiert sind. Das Verständnis dieses Kernunterschieds ist entscheidend für die Entwicklung skalierbarer, wartbarer und performanter Systeme, die unterschiedlichen Client-Bedürfnissen effektiv gerecht werden. Sie sind keine Alternativen, sondern ergänzende Muster, die zusammenarbeiten, um robuste und anpassungsfähige Anwendungen zu erstellen.

