und Tooling im Praxiseinsatz
REST-Endpunkte zu ersetzen ist nicht das Ziel von GraphQL – das Ziel ist, genau die Daten zu laden, die eine Komponente braucht, und sie im richtigen Moment zu cachen. Wer Vue GraphQL ohne Cache-Strategie betreibt, lädt dieselben Daten mehrfach und verliert den größten Vorteil des Ansatzes.
Inhaltsverzeichnis
- 1. Warum Vue und GraphQL so gut zusammenpassen
- 2. Apollo Client in Vue 3 korrekt einrichten
- 3. Queries strukturieren: useQuery und Composables
- 4. InMemoryCache: Normalisierung und Cache-Policies
- 5. Fragments: Queries modular und wiederverwendbar machen
- 6. Mutations und optimistische Updates
- 7. Fehlerbehandlung und Ladezustände richtig abbilden
- 8. Tooling: Apollo DevTools, GraphQL Codegen, VSCode
- 9. Strategien im Vergleich: fetch-policy Optionen
- 10. Zusammenfassung
- 11. FAQ
1. Warum Vue und GraphQL so gut zusammenpassen
Vue GraphQL ist mehr als eine Technologiekombination – es ist ein Paradigmenwechsel in der Art, wie Komponenten Daten konsumieren. In einer klassischen REST-Architektur definiert der Server, welche Daten ein Endpunkt zurückgibt. In einer Vue GraphQL-Architektur definiert die Komponente selbst, welche Felder sie benötigt. Das führt zu weniger Over-Fetching, weniger Under-Fetching und direkt zu schlankerem JavaScript-Payload im Browser.
Der komponentenbasierte Aufbau von Vue passt besonders gut zur Fragment-Architektur von GraphQL. Jede Komponente deklariert ihren eigenen Datenbedarf als Fragment, und der Apollo Client setzt diese Fragmente zu vollständigen Queries zusammen. Das Ergebnis ist, dass Refactoring einer Komponente – das Hinzufügen oder Entfernen von Feldern – automatisch die Query anpasst, ohne dass ein Backend-Entwickler einen neuen Endpunkt implementieren muss. Für Teams, die schnell iterieren, ist Vue GraphQL ein erheblicher Geschwindigkeitsgewinn.
Gleichzeitig bringt Vue GraphQL echter Komplexität mit sich: Cache-Invalidierung, optimistische Updates, Subscription-Handling und das richtige Verständnis des normalisierten Caches sind Themen, die Entwickler ohne Vorbereitung schnell in Schwierigkeiten bringen. Dieser Artikel deckt alle diese Bereiche systematisch ab und zeigt, wie man eine Vue GraphQL-Anwendung so aufbaut, dass sie auch nach einem Jahr ohne grundlegende Umstrukturierung wartbar bleibt.
2. Apollo Client in Vue 3 korrekt einrichten
Der Einstieg in Vue GraphQL beginnt mit der korrekten Konfiguration des Apollo Clients. Das Paket @apollo/client zusammen mit @vue/apollo-composable bildet die Grundlage. Entscheidend ist, dass der Apollo Client als Plugin in die Vue-Applikation eingebunden wird und dabei eine InMemoryCache-Instanz erhält, die bereits initial für die eigene Schema-Struktur konfiguriert ist. Ein häufiger Fehler: Die InMemoryCache wird ohne typePolicies instanziiert, was dazu führt, dass Apollo den Cache nicht korrekt normalisieren kann, sobald Entitäten ohne Standard-id-Felder zurückgegeben werden.
Der ApolloLink ist das Middleware-System des Apollo Clients. Typischerweise besteht die Link-Chain aus einem authLink, der den Authorization-Header anhängt, und einem httpLink, der den eigentlichen HTTP-Request ausführt. Für WebSocket-basierte Subscriptions kommt ein splitLink hinzu, der HTTP-Requests und WebSocket-Verbindungen automatisch auf den richtigen Transport-Channel leitet. Wer diese Konfiguration sauber aufsetzt, vermeidet später schwer debuggbare Authentifizierungsprobleme und Race-Conditions beim Token-Refresh.
// src/plugins/apollo.js
// Apollo Client setup for Vue 3 with auth link and cache policies
import { ApolloClient, InMemoryCache, createHttpLink, from } from '@apollo/client/core'
import { setContext } from '@apollo/client/link/context'
import { provideApolloClient } from '@vue/apollo-composable'
const httpLink = createHttpLink({
uri: import.meta.env.VITE_GRAPHQL_URL,
})
// Attach JWT token to every request
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem('auth_token')
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
},
}
})
const cache = new InMemoryCache({
typePolicies: {
// Normalize Product by slug, not by id
Product: {
keyFields: ['slug'],
},
// Merge paginated lists instead of replacing them
Query: {
fields: {
products: {
keyArgs: ['filter', 'category'],
merge(existing = { items: [] }, incoming) {
return { ...incoming, items: [...existing.items, ...incoming.items] }
},
},
},
},
},
})
export const apolloClient = new ApolloClient({
link: from([authLink, httpLink]),
cache,
defaultOptions: {
watchQuery: { fetchPolicy: 'cache-and-network' },
query: { fetchPolicy: 'network-only', errorPolicy: 'all' },
},
})
// Install into Vue app
export function installApollo(app) {
provideApolloClient(apolloClient)
}
3. Queries strukturieren: useQuery und Composables
In Vue GraphQL mit Composition API ist useQuery aus @vue/apollo-composable die zentrale Funktion für das Laden von Daten. useQuery gibt reaktive Refs zurück: result enthält die Antwortdaten, loading zeigt den Ladezustand an, error enthält aufgetretene Fehler. Diese Refs integrieren sich nahtlos in das reaktive System von Vue 3, sodass Templates automatisch aktualisiert werden, sobald neue Daten eintreffen. Der Query wird reaktiv – ändert sich eine Variable, führt Apollo automatisch einen neuen Fetch durch.
Queries gehören nicht direkt in Komponenten, sondern in dedizierte Composables im Ordner src/composables/. Das hat mehrere Vorteile: Das Composable kann in mehreren Komponenten wiederverwendet werden, die Query-Logik ist testbar ohne das Rendern einer Komponente, und die Komponente selbst bleibt schlank und auf die Darstellung fokussiert. Das Muster useProduct(slug) als Composable, das intern useQuery aufruft und nach außen nur { product, loading, error } exponiert, ist das Standardmuster in gut strukturierten Vue GraphQL-Projekten.
4. InMemoryCache: Normalisierung und Cache-Policies
Der InMemoryCache ist das Herzstück jeder Vue GraphQL-Anwendung mit Apollo Client. Er funktioniert als normalisierter, flacher Datenspeicher: Jede Entität wird unter einem Schlüssel aus Typ und ID gespeichert, zum Beispiel Product:42. Wenn mehrere Queries dieselbe Entität zurückgeben, wird sie nur einmal im Cache gespeichert. Jede Komponente, die diese Entität abonniert, erhält automatisch das Update, sobald eine Mutation die Entität verändert. Dieses Konzept ist der entscheidende Unterschied zwischen Apollo-basiertem Vue GraphQL und einem einfachen fetch-Aufruf in einem Composable.
Die typePolicies-Konfiguration ist der Schlüssel zu einem korrekt funktionierenden Cache. Mit keyFields legt man fest, welche Felder den eindeutigen Schlüssel einer Entität bilden. Mit merge-Funktionen steuert man, wie eingehende Daten mit bestehenden Daten zusammengeführt werden – entscheidend für Pagination, bei der neue Seiten an bestehende Listen angehängt werden sollen. Mit read-Funktionen transformiert man Daten beim Lesen aus dem Cache, zum Beispiel um clientseitig berechnete Felder hinzuzufügen. Wer typePolicies sorgfältig konfiguriert, baut eine Vue GraphQL-Anwendung, in der Datenkonsistenz automatisch gewährleistet ist.
5. Fragments: Queries modular und wiederverwendbar machen
GraphQL-Fragments sind in Vue GraphQL-Projekten das Mittel, um Queries modular und wartbar zu halten. Ein Fragment definiert eine benannte Auswahl von Feldern für einen bestimmten Typ. Die Komponente, die diese Daten darstellt, definiert ihr Fragment, und die übergeordnete Query schließt dieses Fragment ein. Das Ergebnis: Wenn die Produktkarte-Komponente ein neues Feld braucht, wird nur das Fragment der Produktkarte angepasst – die Query auf der Listenseite, die das Fragment einschließt, aktualisiert sich automatisch.
Apollo Client kann Fragment-Daten auch direkt aus dem Cache lesen und schreiben, ohne eine vollständige Query auszuführen. Die Methode cache.readFragment liest eine Entität nach Typ und ID aus dem Cache. cache.writeFragment schreibt Daten in den Cache, ohne einen Netzwerk-Request auszuführen. Dieses Muster ist für optimistische Updates unverzichtbar: Man schreibt die erwartete Antwort bereits vor der Mutation in den Cache, und die Komponente zeigt sofort den neuen Zustand an – erst wenn die Mutation abgeschlossen ist, wird der Cache mit der tatsächlichen Server-Antwort überschrieben.
// src/graphql/fragments/product.js
// Reusable product fragment — import in any query that needs product data
import { gql } from '@apollo/client/core'
export const PRODUCT_CARD_FRAGMENT = gql`
fragment ProductCard on Product {
id
slug
name
price {
amount
currency
}
thumbnail {
url
altText
}
inStock
}
`
export const PRODUCT_DETAIL_FRAGMENT = gql`
fragment ProductDetail on Product {
...ProductCard
description
images {
url
altText
width
height
}
variants {
id
sku
attributes { name value }
price { amount currency }
}
}
${PRODUCT_CARD_FRAGMENT}
`
// src/composables/useProducts.js
// Composable that exposes paginated product list
import { useQuery } from '@vue/apollo-composable'
import { gql } from '@apollo/client/core'
import { PRODUCT_CARD_FRAGMENT } from '@/graphql/fragments/product'
import { computed, ref } from 'vue'
const PRODUCTS_QUERY = gql`
query Products($filter: ProductFilter, $page: Int!) {
products(filter: $filter, page: $page, perPage: 24) {
total
items { ...ProductCard }
}
}
${PRODUCT_CARD_FRAGMENT}
`
export function useProducts(filter) {
const page = ref(1)
const { result, loading, error, fetchMore } = useQuery(PRODUCTS_QUERY, () => ({
filter: filter.value,
page: page.value,
}), { fetchPolicy: 'cache-and-network' })
const products = computed(() => result.value?.products?.items ?? [])
const total = computed(() => result.value?.products?.total ?? 0)
function loadMore() {
page.value++
fetchMore({ variables: { page: page.value } })
}
return { products, total, loading, error, loadMore }
}
6. Mutations und optimistische Updates
Mutations in Vue GraphQL mit Apollo werden über useMutation aus @vue/apollo-composable ausgeführt. Im Gegensatz zu useQuery wird eine Mutation nicht automatisch ausgeführt, sondern nur auf expliziten Aufruf der zurückgegebenen mutate-Funktion. Das wichtigste Feature für eine gute User Experience ist die optimisticResponse-Option: Man gibt die erwartete Antwort der Mutation an, bevor der Request überhaupt gesendet wurde. Apollo schreibt diese optimistische Antwort sofort in den Cache, und alle abhängigen Queries und Komponenten aktualisieren sich unmittelbar. Sobald die echte Antwort vom Server eintrifft, überschreibt Apollo die optimistische Antwort mit den tatsächlichen Daten.
Cache-Updates nach Mutations sind in Vue GraphQL ein häufiges Thema. Wenn eine Mutation eine neue Entität erstellt, ist diese noch nicht im Cache. Man muss den Cache manuell aktualisieren, indem man in der update-Funktion der Mutation die bestehende Liste aus dem Cache liest, die neue Entität hinzufügt und die Liste zurück in den Cache schreibt. Wenn die Mutation eine bestehende Entität aktualisiert, geschieht das automatisch – Apollo normalisiert die Antwort und aktualisiert die Entität im Cache unter dem bekannten Schlüssel. Wer dieses Verhalten versteht, braucht nach Mutations nur selten einen expliziten refetch.
7. Fehlerbehandlung und Ladezustände richtig abbilden
Fehlerbehandlung in Vue GraphQL hat zwei Ebenen: Netzwerkfehler, bei denen der Request gar nicht oder mit einem HTTP-Fehlercode zurückkommt, und GraphQL-Errors, bei denen der Request erfolgreich war, aber das Schema Validierungsfehler oder applikationsseitige Fehler zurückgibt. Apollo unterscheidet zwischen diesen beiden Fehlerarten, und die richtige Konfiguration der errorPolicy entscheidet, wie mit gemischten Antworten umgegangen wird – also Antworten, die teilweise Daten und teilweise Errors enthalten. Mit errorPolicy: 'all' werden sowohl Daten als auch Errors zurückgegeben, was in komplexen Queries sinnvoll ist, bei denen ein Fehler in einem Zweig nicht die gesamte Query invalidieren soll.
Ladezustände in Vue GraphQL-Komponenten sollten explizit designed werden. Ein häufiger Fehler ist, einfach mit v-if="!loading" den gesamten Inhalt auszublenden. Das führt zu Layout-Shifts und einer schlechten User Experience. Besser ist ein Skeleton-Loading-Pattern: Die Komponente rendert bei loading === true eine Platzhalterversion mit derselben Struktur und denselben Dimensionen wie der eigentliche Inhalt. Vue GraphQL macht dieses Muster einfach, weil der reaktive loading-Ref direkt im Template ausgewertet werden kann.
8. Tooling: Apollo DevTools, GraphQL Codegen, VSCode
Das Tooling-Ökosystem rund um Vue GraphQL ist ausgereift und beschleunigt die Entwicklung erheblich. Die Apollo Client DevTools für Chrome und Firefox erlauben, den gesamten Cache zu inspizieren, aktive Queries und Mutations zu sehen und Queries direkt im Browser auszuführen. Wer einmal den normalisierten Cache in den DevTools gesehen hat – wie jede Entität unter ihrem Schlüssel gespeichert ist und wie Queries auf Cache-Einträge verweisen – versteht das Apollo-Caching-Modell viel schneller als durch bloßes Lesen der Dokumentation.
GraphQL Code Generator ist für größere Vue GraphQL-Projekte unverzichtbar. Das Tool liest das GraphQL-Schema und alle .graphql-Dateien im Projekt und generiert daraus TypeScript-Typen für alle Queries, Mutations und Fragments. Das Ergebnis: Vollständige Typsicherheit zwischen GraphQL-Schema und Vue-Komponenten. Wenn ein Feld im Schema umbenannt wird, zeigt TypeScript sofort alle betroffenen Stellen im Frontend an. Die Konfiguration ist minimal – ein codegen.yml reicht aus – und die Integration in den Entwicklungsserver mit --watch generiert Typen bei jeder Schemaänderung automatisch neu.
// codegen.yml — GraphQL Code Generator config for Vue 3 + TypeScript
// Run: npx graphql-code-generator --config codegen.yml --watch
// Generates typed hooks and fragment types from schema + operations
overwrite: true
schema: "${VITE_GRAPHQL_URL}"
documents: "src/**/*.{graphql,gql,ts,vue}"
generates:
src/generated/graphql.ts:
plugins:
- typescript
- typescript-operations
- typescript-vue-apollo
config:
vueCompositionApiImportFrom: vue
withCompositionFunctions: true
withSmartQuery: false
useTypeImports: true
// After generation — fully typed composable usage
// src/composables/useProduct.ts
import { useProductQuery } from '@/generated/graphql'
import { computed } from 'vue'
export function useProduct(slug: string) {
// useProductQuery is auto-generated — fully typed result, variables, etc.
const { result, loading, error } = useProductQuery(
() => ({ slug }),
{ fetchPolicy: 'cache-and-network' }
)
const product = computed(() => result.value?.product ?? null)
return { product, loading, error }
}
9. Strategien im Vergleich: fetch-policy Optionen
Die fetchPolicy einer Query ist eine der wichtigsten Stellschrauben in jeder Vue GraphQL-Anwendung. Die falsche Policy führt entweder zu unnötig vielen Netzwerkanfragen oder zu veralteten Daten, die der User zu sehen bekommt. Das Verstehen der verfügbaren Optionen ist grundlegend für eine performante Vue GraphQL-Architektur.
| fetchPolicy | Cache lesen? | Netzwerk-Request? | Idealer Einsatz |
|---|---|---|---|
cache-first |
Ja (primär) | Nur bei Cache-Miss | Statische Referenzdaten, Kategorien |
cache-and-network |
Ja (sofort) | Immer | Listen mit häufigen Updates |
network-only |
Nein | Immer | Kritische Daten, Checkout |
cache-only |
Ja | Nie | Offline-Szenarien, optimistische UI |
no-cache |
Nein | Immer | Sensitive Daten ohne Cache-Speicherung |
Im Entwickleralltag empfiehlt sich folgende Faustregel für Vue GraphQL-Projekte: cache-and-network als Standard für alle Listen und Detailseiten, weil der User sofort Daten aus dem Cache sieht und im Hintergrund der aktuellste Stand geladen wird. network-only für transaktionale Queries wie Bestellstatus oder Kontosaldo, wo veraltete Daten kritische Konsequenzen haben können. cache-first für Konfigurationsdaten und statische Listen wie Kategorien oder Länderauswahlen, die sich nur bei Deploys ändern.
Mironsoft
Vue GraphQL · Apollo Client · TypeScript · Frontend-Architektur
Vue GraphQL-Architektur für euer Projekt?
Wir konzipieren und implementieren Vue GraphQL-Integrationen mit Apollo Client – von der Cache-Strategie über typisierte Composables bis zum vollständigen GraphQL Code Generator-Setup.
Schema-Design
GraphQL-Schema entwerfen, typePolicies konfigurieren und Fragments strukturieren
Performance-Optimierung
fetchPolicy-Strategie, Pagination mit fetchMore und optimistische Updates
Code-Generierung
GraphQL Code Generator einrichten und typsichere Composables generieren
10. Zusammenfassung
Vue GraphQL mit Apollo Client ist kein Drop-in-Ersatz für REST-Aufrufe, sondern ein vollständiges Datenverwaltungssystem für Frontend-Anwendungen. Der normalisierte Cache ist der zentrale Vorteil: Jede Entität wird einmal gespeichert, und Mutations aktualisieren automatisch alle abhängigen Views. Fragments machen Queries modular und an Komponenten gekoppelt. Die fetchPolicy steuert das Verhältnis zwischen Cache-Effizienz und Datenfreshness. Optimistische Updates geben dem User sofortiges Feedback, ohne auf die Server-Antwort zu warten.
Das Tooling rund um Vue GraphQL ist ausgereift: Apollo DevTools für Cache-Inspektion, GraphQL Code Generator für typsichere Composables und die VSCode-GraphQL-Extension für Syntax-Highlighting und Auto-Completion direkt in Query-Strings. Wer diese Tools von Anfang an in ein Projekt integriert, baut schneller, macht weniger Fehler und kann Refactorings mit Konfidenz durchführen, weil TypeScript und der Generator sofort auf Inkonsistenzen hinweisen.
Vue GraphQL — Das Wichtigste auf einen Blick
Cache-Normalisierung
typePolicies und keyFields konfigurieren – jede Entität wird einmal gespeichert und automatisch durch Mutations aktualisiert.
Fragments & Composables
Komponenten deklarieren eigene Fragments, Composables kapseln useQuery – Queries bleiben wartbar und wiederverwendbar.
fetchPolicy-Strategie
cache-and-network als Standard, network-only für transaktionale Daten, cache-first für statische Listen.
Code Generator
GraphQL Code Generator generiert TypeScript-Typen und typisierte Composables – vollständige Typsicherheit zwischen Schema und Vue.