Wann sich eine Kombination aus beiden Protokollen lohnt, statt komplett zu migrieren
Die Diskussion um GraphQL und REST wird oft als Entweder-oder geführt, dabei schließen sich beide Protokolle in der Praxis nicht aus. REST bleibt für einfache CRUD-Ressourcen und Webhooks die pragmatische Wahl, GraphQL spielt seine Stärken bei komplexen, aggregierenden Leseoperationen im Frontend aus. Dieser Artikel zeigt, wie eine hybride Architektur mit gemeinsamer Backend-Logik konkret aussieht, was sie an Team- und Tooling-Aufwand kostet und wann sich die zusätzliche Komplexität schlicht nicht lohnt.
Inhaltsverzeichnis
- 1. Warum die Wahl selten ein Entweder-oder ist
- 2. Typische Aufteilung: REST für CRUD, GraphQL für aggregierende Leseoperationen
- 3. Gemeinsame Backend-Logik hinter beiden Schnittstellen
- 4. Team- und Tooling-Kosten einer Zwei-Protokoll-Strategie
- 5. Caching-Verhalten: HTTP-Caching versus Query-spezifisches Caching
- 6. Versionierung und Schema-Evolution im Vergleich
- 7. Sicherheitsaspekte: Rate-Limiting und Query-Komplexität
- 8. Wann sich die zusätzliche Komplexität nicht lohnt
- 9. Entscheidungshilfe für die eigene Architektur
- 10. Zusammenfassung
- 11. FAQ
1. Warum die Wahl selten ein Entweder-oder ist
Die Diskussion um GraphQL und REST wird in vielen Teams als Grundsatzentscheidung geführt, bei der ein Protokoll das andere vollständig ablösen soll. In der Praxis zeigt sich jedoch regelmäßig, dass diese Entweder-oder-Haltung an den tatsächlichen Anforderungen vorbeigeht, weil beide Protokolle für unterschiedliche Zugriffsmuster unterschiedlich gut geeignet sind. Ein Team, das GraphQL ausschließlich einführt, um ein bestehendes REST-Backend zu ersetzen, überträgt oft Probleme, die REST gar nicht hatte, in eine neue, komplexere Schicht.
Sinnvoller ist es, GraphQL dort einzusetzen, wo es seine Stärken tatsächlich ausspielt, und REST dort zu belassen, wo es bereits gut funktioniert. Diese hybride Denkweise verlangt zwar eine bewusste Architekturentscheidung und etwas mehr Abstimmungsaufwand im Team, vermeidet aber die Kosten einer kompletten Migration, deren Nutzen in vielen Projekten den Aufwand gar nicht rechtfertigt. Der Rest dieses Artikels beschreibt, wie eine solche Aufteilung in der Praxis aussieht und wo ihre Grenzen liegen.
2. Typische Aufteilung: REST für CRUD, GraphQL für aggregierende Leseoperationen
Eine bewährte Aufteilung ordnet REST die einfachen CRUD-Ressourcen zu, also das Anlegen, Lesen, Aktualisieren und Löschen einzelner, klar abgegrenzter Entitäten wie Bestellungen, Kunden oder Produkte. Für diese Operationen bietet REST mit seinen etablierten HTTP-Methoden, Statuscodes und der einfachen Testbarkeit über curl oder Postman einen unmittelbaren Vorteil, ohne dass ein zusätzliches Abfrageschema notwendig wäre. Auch Webhooks, also ausgehende Benachrichtigungen an externe Systeme bei Ereignissen, passen strukturell besser zu REST, weil sie im Kern einfache, einzelne POST-Requests mit einem festen Payload-Format sind.
GraphQL entfaltet seinen Vorteil dagegen bei komplexen, aggregierenden Leseoperationen im Frontend, bei denen eine einzelne Ansicht Daten aus mehreren, tief verschachtelten Ressourcen benötigt. Eine Produktdetailseite, die gleichzeitig Preisdaten, Lagerbestand, Bewertungen und verwandte Produkte anzeigen soll, würde mit REST mehrere separate Requests erfordern oder einen speziell zugeschnittenen Endpunkt, während GraphQL genau diese Kombination in einer einzigen Anfrage erlaubt. Für Frontend-Teams, die häufig neue Ansichten mit wechselnden Datenkombinationen bauen, reduziert das den Abstimmungsaufwand mit dem Backend-Team spürbar.
3. Gemeinsame Backend-Logik hinter beiden Schnittstellen
Damit die Einführung von GraphQL neben REST nicht zu doppelt gepflegter Geschäftslogik führt, sollte die eigentliche Domänenlogik in einer gemeinsamen Service-Schicht liegen, auf die sowohl REST-Controller als auch GraphQL-Resolver zugreifen. In einer Symfony-Anwendung bedeutet das konkret, dass ein Anwendungsfall wie das Abrufen einer Bestellung als eigenständiger Service implementiert wird, der weder von der HTTP-Schicht noch vom GraphQL-Schema abhängt.
Dieses Muster verhindert, dass Validierungsregeln, Berechtigungsprüfungen oder Berechnungslogik zweimal implementiert werden und in der Folge auseinanderlaufen. Der REST-Controller und der GraphQL-Resolver werden dadurch zu dünnen Adapterschichten, die lediglich zwischen dem jeweiligen Protokollformat und der gemeinsamen Domänenschicht übersetzen, was auch das Testen erheblich vereinfacht, weil die eigentliche Logik unabhängig vom Transportprotokoll getestet werden kann.
<?php
declare(strict_types=1);
namespace App\Order\Application;
final class GetOrderService
{
public function __construct(
private readonly OrderRepositoryInterface $orderRepository,
) {
}
/**
* Lädt eine Bestellung anhand ihrer ID.
* Wird sowohl vom REST Controller als auch vom GraphQL Resolver genutzt.
*/
public function execute(string $orderId): Order
{
$order = $this->orderRepository->findById($orderId);
if ($order === null) {
throw new OrderNotFoundException($orderId);
}
return $order;
}
}
// REST Controller (dünner Adapter)
final class OrderController
{
public function __construct(private readonly GetOrderService $getOrderService)
{
}
public function show(string $orderId): JsonResponse
{
$order = $this->getOrderService->execute($orderId);
return new JsonResponse(OrderNormalizer::normalize($order));
}
}
// GraphQL Resolver (dünner Adapter, gleiche Service Schicht)
final class OrderResolver
{
public function __construct(private readonly GetOrderService $getOrderService)
{
}
public function resolveOrder(string $orderId): Order
{
return $this->getOrderService->execute($orderId);
}
}
4. Team- und Tooling-Kosten einer Zwei-Protokoll-Strategie
Der Preis einer Zwei-Protokoll-Strategie zeigt sich selten sofort, sondern erst über die Zeit im laufenden Betrieb. Zwei Schnittstellen bedeuten zwei Sätze an Dokumentation, die synchron gehalten werden müssen, zwei unterschiedliche Testansätze (Contract-Tests für REST, Schema-Validierung und Query-Tests für GraphQL) und zwei Monitoring-Strategien, weil sich Fehlerraten und Latenzen bei GraphQL nicht mehr sauber pro Endpunkt, sondern pro Feld oder Resolver messen lassen.
Auch das Team selbst muss beide Denkweisen beherrschen: REST-Ressourcenmodellierung folgt anderen Prinzipien als GraphQL-Schema-Design mit Typen, Interfaces und Resolvern, und nicht jeder Entwickler bringt beides gleich gut mit. Kleinere Teams unterschätzen häufig, wie viel zusätzliche Abstimmung nötig ist, um zu entscheiden, welche neue Anforderung über welches Protokoll umgesetzt wird, bevor sich diese Entscheidung als Team-Konvention etabliert hat.
5. Caching-Verhalten: HTTP-Caching versus Query-spezifisches Caching
REST profitiert direkt von HTTP-Caching-Mechanismen wie ETag, Last-Modified und Cache-Control-Headern, die von Browsern, CDNs und Reverse-Proxys wie Varnish ohne zusätzliche Konfiguration verstanden werden. Ein GET-Request auf eine Produktressource lässt sich dadurch mit vergleichsweise geringem Aufwand cachen, weil die URL selbst eindeutig identifiziert, welche Ressource gemeint ist.
GraphQL erschwert dieses Muster strukturell, weil praktisch alle Anfragen über denselben Endpunkt per POST laufen und der eigentliche Inhalt der Anfrage im Request-Body steckt, den HTTP-Caches standardmäßig nicht auswerten. Caching muss deshalb entweder auf Anwendungsebene mit einem Persisted-Queries-Mechanismus oder einem GraphQL-spezifischen Cache wie Apollo Server Cache-Control-Direktiven nachgebaut werden, was zusätzliche Infrastruktur und zusätzliches Know-how im Team voraussetzt.
6. Versionierung und Schema-Evolution im Vergleich
REST-APIs werden traditionell über URL-Präfixe oder Header versioniert, etwa /v1/orders und /v2/orders, wenn sich das Ressourcenformat inkompatibel ändert. Diese Versionierung ist explizit sichtbar, erfordert aber, dass alte Versionen parallel gepflegt werden, solange noch Konsumenten darauf zugreifen.
GraphQL verfolgt bewusst einen anderen Ansatz: Statt expliziter Versionen wird das Schema evolutionär erweitert, neue Felder kommen hinzu, veraltete Felder werden mit einem @deprecated-Hinweis markiert, aber nicht sofort entfernt. Das funktioniert gut, solange Breaking Changes tatsächlich vermieden werden, verlangt aber Disziplin bei der Schema-Pflege, weil sich veraltete Felder in der Praxis oft länger halten, als ursprünglich geplant war.
7. Sicherheitsaspekte: Rate-Limiting und Query-Komplexität
Bei REST lässt sich Rate-Limiting vergleichsweise einfach pro Endpunkt und HTTP-Methode konfigurieren, weil jede Ressource und jede Operation eine eigene, klar identifizierbare URL hat. Ein API-Gateway kann dadurch granular steuern, wie oft ein Client bestimmte Operationen aufrufen darf.
GraphQL braucht hier einen anderen Schutzmechanismus, weil eine einzelne Anfrage durch tiefe Verschachtelung theoretisch beliebig teuer für das Backend werden kann, selbst wenn sie technisch nur ein einziger Request ist. Üblich sind deshalb Query-Complexity-Analysen, die jeder Anfrage vor der Ausführung einen Kostenwert zuweisen, und eine maximale Verschachtelungstiefe, die im Schema oder in der Middleware durchgesetzt wird, um übermäßig teure Anfragen von vornherein abzulehnen.
8. Wann sich die zusätzliche Komplexität nicht lohnt
Nicht jedes Projekt profitiert von einer Hybrid-Strategie. Bei einer überschaubaren Domäne mit wenigen, klar abgegrenzten Ressourcen und einem einzigen Frontend-Team, das die API konsumiert, rechtfertigt der Zusatzaufwand einer zweiten Schnittstelle in den meisten Fällen den Nutzen nicht. Der zusätzliche Betriebs-, Test- und Dokumentationsaufwand für GraphQL lohnt sich vor allem dann, wenn tatsächlich mehrere Frontend-Teams mit unterschiedlichen, sich häufig ändernden Datenanforderungen gegen dieselbe API arbeiten.
Auch kleine Teams ohne dedizierte Erfahrung mit GraphQL-Schema-Design sollten die Einführung kritisch hinterfragen, denn ein schlecht entworfenes GraphQL-Schema mit N+1-Problemen und fehlender Query-Complexity-Kontrolle kann mehr Probleme verursachen, als es löst. In solchen Fällen ist ein gut modelliertes REST-API mit gezielten, auf die Frontend-Bedürfnisse zugeschnittenen Aggregations-Endpunkten häufig die pragmatischere und wartungsärmere Lösung.
9. Entscheidungshilfe für die eigene Architektur
Die folgende Tabelle fasst die zentralen Entscheidungskriterien zusammen, um im konkreten Projekt schneller abzuwägen, ob und in welchem Umfang sich eine Hybrid-Strategie aus REST und GraphQL lohnt.
| Kriterium | REST | GraphQL | Empfehlung |
|---|---|---|---|
| Ressourcen-Caching | Einfach über HTTP-Header | Erfordert zusätzliche Infrastruktur | REST für stark gecachte Leseressourcen |
| Aggregierende Leseabfragen | Mehrere Requests nötig | Eine Anfrage für verschachtelte Daten | GraphQL für komplexe Frontend-Views |
| Webhooks und Events | Natives Muster | Unüblich, kein Standard | REST für ausgehende Benachrichtigungen |
| Schutz vor teuren Anfragen | Pro Endpunkt/Rate-Limit | Query-Complexity-Analyse nötig | Zusätzlichen Aufwand bei GraphQL einplanen |
| Team-Einarbeitung | Breit bekannt | Eigenes Schema-Denken nötig | GraphQL nur bei tatsächlichem Bedarf einführen |
Mironsoft
OpenAPI-Design, Symfony-APIs und API-Sicherheit
APIs, die externe Teams ohne Rückfragen integrieren können?
Wir prüfen bestehende REST-APIs auf inkonsistente Fehlerformate, fehlende OpenAPI-Dokumentation und Sicherheitslücken und bauen daraus eine API, die klar dokumentiert, versioniert und gegen Missbrauch abgesichert ist.
API-Review
OpenAPI-Spezifikation, Fehlerformate und Statuscodes auf Konsistenz prüfen.
Symfony-Umsetzung
DTOs, Serializer und Validator für saubere, typsichere Request/Response-Modelle einsetzen.
Security-Audit
Rate-Limiting, Auth-Schemes und Input-Validierung gegen echte Angriffsflächen absichern.
10. Zusammenfassung
GraphQL und REST Hybrid: Das Wichtigste auf einen Blick
Kernidee
GraphQL und REST schließen sich nicht aus, sie decken unterschiedliche Zugriffsmuster ab und lassen sich hinter derselben Backend-Logik kombinieren.
Typische Aufteilung
REST für CRUD-Ressourcen und Webhooks, GraphQL für komplexe, aggregierende Leseoperationen im Frontend.
Größter Kostenfaktor
Doppelte Dokumentation, doppeltes Testing und ein Team, das beide Denkweisen gleichzeitig beherrschen muss.
Wann es sich nicht lohnt
Bei kleinen Domänen mit einem einzigen Frontend-Team ist ein gut modelliertes REST-API meist die einfachere Wahl.