Typen automatisch aus dem Schema erzeugen
Manuell gepflegte TypeScript-Interfaces fuer GraphQL-Typen laufen fast zwangslaeufig irgendwann aus dem Ruder, sobald sich das Schema aendert. GraphQL Code Generator loest dieses Problem, indem Server-Resolver-Typen, Client-Operation-Typen und sogar fertige React-Hooks direkt und automatisch aus einer einzigen Schema-Datei erzeugt werden.
Inhaltsverzeichnis
- 1. Das Problem manuell gepflegter GraphQL-Typen
- 2. Installation und Grundkonfiguration von codegen.yml
- 3. Typen fuer das Schema selbst generieren
- 4. Typisierte Resolver mit typescript-resolvers
- 5. Client-seitige Typen mit typed-document-node
- 6. React-Hooks fuer Queries generieren lassen
- 7. Codegen in CI/CD und Watch-Mode integrieren
- 8. Near-Operation-File-Preset und modulare Ausgabe
- 9. Code Generator im Vergleich zu manuellen Typen und tRPC
- 10. Zusammenfassung
- 11. FAQ
1. Das Problem manuell gepflegter GraphQL-Typen
GraphQL bringt mit seinem Schema bereits eine vollstaendige, sprachunabhaengige Typbeschreibung mit, dennoch schreiben viele Teams die entsprechenden TypeScript-Interfaces von Hand nach. Das Ergebnis ist vorhersehbar: Aendert sich ein Feld im Schema, muss diese Aenderung manuell in jedes betroffene Interface uebertragen werden, was in groesseren Projekten mit vielen Queries schnell zu vergessenen Stellen und stillen Typ-Inkonsistenzen fuehrt.
GraphQL Code Generator loest dieses Problem, indem es das Schema als einzige Quelle der Wahrheit behandelt und daraus automatisch alle benoetigten TypeScript-Typen erzeugt, sowohl fuer den Server als auch fuer den Client. Der Werkzeugkasten besteht aus einem Kern-Paket und einer Vielzahl von Plugins, die jeweils fuer einen bestimmten Ausgabestil zustaendig sind, etwa fuer Resolver-Typen, fuer typisierte Dokumente oder fuer fertige React-Hooks.
Fuer TypeScript-Teams, die bereits GraphQL im Einsatz haben, ist der Umstieg auf generierte Typen meist eine der wirkungsvollsten einzelnen Massnahmen gegen Typ-Drift zwischen Frontend und Backend. Dieser Artikel zeigt den Weg von der Grundkonfiguration bis zur Integration in die CI-Pipeline.
2. Installation und Grundkonfiguration von codegen.yml
Die Konfiguration von GraphQL Code Generator erfolgt ueber eine codegen.yml-Datei im Projektwurzelverzeichnis, die mindestens drei Angaben braucht: den Pfad oder die URL zum Schema, die zu durchsuchenden Dokumente mit GraphQL-Operationen, und eine Liste von Ausgabedateien mit den jeweils gewuenschten Plugins. Diese Struktur erlaubt es, mehrere unterschiedliche Ausgaben aus demselben Schema zu erzeugen, etwa Server-Typen in einer Datei und Client-Typen in einer anderen.
Ein haeufiger Anfaengerfehler: Das Schema wird als lokale, statische Datei referenziert, obwohl es sich haeufig aendert, was dazu fuehrt, dass Entwickler vergessen, die Schema-Datei vor dem Generieren zu aktualisieren. Fuer Projekte mit einem lebenden GraphQL-Server ist es meist robuster, direkt auf die Introspection-URL des laufenden Servers zu verweisen, sodass Code Generator immer den aktuellen Stand abfragt.
// codegen.ts — root configuration for GraphQL Code Generator
import type { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = {
schema: "http://localhost:4000/graphql",
documents: ["src/**/*.graphql", "src/**/*.tsx"],
generates: {
"src/generated/graphql.ts": {
plugins: [
"typescript",
"typescript-operations",
"typescript-react-apollo",
],
},
"src/generated/schema-types.ts": {
plugins: ["typescript", "typescript-resolvers"],
},
},
};
export default config;
3. Typen fuer das Schema selbst generieren
Das Basis-Plugin typescript erzeugt fuer jeden Typ im GraphQL-Schema ein entsprechendes TypeScript-Interface, inklusive Enums, Union-Typen und Input-Typen. Diese Typen bilden die Grundlage fuer alle weiteren Plugins und werden selten direkt in Anwendungscode verwendet, dienen aber als gemeinsame Basis, auf der Resolver-Typen und Operation-Typen aufbauen.
Wichtig fuer TypeScript mit GraphQL Code Generator: Skalare Typen wie DateTime oder JSON, die ueber die GraphQL-Standardtypen hinausgehen, muessen in der Konfiguration explizit einem konkreten TypeScript-Typ zugeordnet werden. Ohne diese Zuordnung fallen benutzerdefinierte Skalare standardmaessig auf any zurueck, was einen Teil der gewonnenen Typsicherheit sofort wieder zunichtemacht.
4. Typisierte Resolver mit typescript-resolvers
Das Plugin typescript-resolvers erzeugt fuer jeden Typ im Schema einen passenden Resolver-Typ, der Parent-Typ, Argumente und Rueckgabetyp bereits korrekt typisiert. Ein Server-Entwickler muss dadurch keine Resolver-Signaturen mehr von Hand schreiben oder gegen das Schema abgleichen, der generierte Typ garantiert, dass die Resolver-Implementierung exakt dem deklarierten Schema entspricht.
Besonders wertvoll ist dieses Plugin bei Aenderungen am Schema: Wird ein Feld umbenannt oder ein Argument entfernt, meldet der Compiler sofort einen Fehler in jedem Resolver, der die alte Signatur noch erwartet. Diese Rueckkopplung verhindert, dass ein Resolver nach einer Schema-Aenderung unbemerkt falsche oder veraltete Daten zurueckgibt.
// resolvers/post.ts — generated Resolvers type enforces the schema contract
import type { Resolvers } from "../generated/schema-types";
export const postResolvers: Resolvers = {
Query: {
post: async (_parent, args, ctx) => {
// args.id is typed as string, derived directly from the schema
return ctx.postService.findById(args.id);
},
},
Post: {
// Field resolver: parent is typed as the generated Post type
author: async (parent, _args, ctx) => {
return ctx.userService.findById(parent.authorId);
},
},
};
5. Client-seitige Typen mit typed-document-node
Das Plugin typed-document-node erzeugt fuer jede GraphQL-Operation, also jede Query, Mutation oder Subscription, ein TypedDocumentNode-Objekt, das gleichzeitig als ausfuehrbares GraphQL-Dokument und als Typtraeger fuer Variablen und Ergebnis dient. Client-Bibliotheken wie Apollo Client oder urql erkennen diesen Typ automatisch, sodass ein Aufruf wie useQuery(GetPostDocument) ohne manuelle Typangabe bereits vollstaendig typisierte Ergebnisse liefert.
Dieser Ansatz ist bibliotheksunabhaengiger als reine Hook-Generierung, weil TypedDocumentNode von den meisten modernen GraphQL-Clients unterstuetzt wird, ohne dass ein spezifisches Client-Plugin noetig waere. Fuer Teams, die zwischen verschiedenen GraphQL-Clients wechseln koennten oder mehrere Clients parallel nutzen, ist typed-document-node deshalb oft die zukunftssicherere Wahl gegenueber client-spezifischen Hook-Generatoren.
// generated/graphql.ts (excerpt) — typed document for a single query
import type { TypedDocumentNode } from "@graphql-typed-document-node/core";
export type GetPostQuery = {
post: { id: string; title: string; author: { name: string } };
};
export type GetPostQueryVariables = {
id: string;
};
export const GetPostDocument: TypedDocumentNode<
GetPostQuery,
GetPostQueryVariables
> = /* generated GraphQL document */ null as unknown as TypedDocumentNode<
GetPostQuery,
GetPostQueryVariables
>;
// component.tsx — no manual generics needed, types come from the document
import { useQuery } from "@apollo/client";
import { GetPostDocument } from "./generated/graphql";
function PostView({ id }: { id: string }) {
const { data } = useQuery(GetPostDocument, { variables: { id } });
// data?.post.title is fully typed, no cast required
return <p>{data?.post.title}</p>;
}
6. React-Hooks fuer Queries generieren lassen
Neben typed-document-node bietet GraphQL Code Generator auch client-spezifische Plugins wie typescript-react-apollo, die fuer jede Query direkt einen fertigen, benannten Hook erzeugen, etwa useGetPostQuery. Dieser Ansatz reduziert Boilerplate weiter, weil Entwickler weder den Dokument-Import noch die Typ-Generics selbst verwalten muessen, der generierte Hook kapselt beides bereits vollstaendig.
Der Kompromiss dieses Ansatzes: Die generierten Hooks binden den Code enger an eine bestimmte Client-Bibliothek. Ein spaeterer Wechsel von Apollo Client zu urql erfordert dann nicht nur eine Aenderung der Codegen-Konfiguration, sondern auch das Ersetzen aller Hook-Aufrufe im Anwendungscode. Fuer Teams, die sich langfristig auf eine Client-Bibliothek festlegen, ist dieser Mehraufwand meist akzeptabel, fuer Teams mit hoher Unsicherheit ueber die Client-Wahl ist typed-document-node die flexiblere Alternative.
7. Codegen in CI/CD und Watch-Mode integrieren
Der Aufruf graphql-codegen --watch beobachtet Aenderungen am Schema und an den GraphQL-Dokumenten und regeneriert die Typen automatisch bei jeder Aenderung, was sich hervorragend fuer die lokale Entwicklung eignet. Fuer die CI-Pipeline ist stattdessen ein einmaliger Lauf mit anschliessender Pruefung sinnvoll: graphql-codegen gefolgt von git diff --exit-code stellt sicher, dass niemand vergessen hat, generierte Dateien nach einer Schema-Aenderung erneut einzuchecken.
Diese Pruefung ist besonders wichtig, weil generierte Dateien in vielen Projekten versioniert werden, um Build-Zeiten zu verkuerzen und CI-Laeufe unabhaengig von einem laufenden GraphQL-Server zu machen. Ohne diese CI-Pruefung koennen veraltete, eingecheckte generierte Typen unbemerkt von der tatsaechlichen Schema-Definition abweichen, was die urspruengliche Absicht von GraphQL Code Generator untergraebt.
8. Near-Operation-File-Preset und modulare Ausgabe
Standardmaessig erzeugt GraphQL Code Generator eine einzige, oft sehr grosse Ausgabedatei mit allen Typen des Projekts. Das near-operation-file-Preset aendert dieses Verhalten: Fuer jede Datei mit einer GraphQL-Operation wird eine eigene, benachbarte generierte Datei erzeugt, etwa GetPost.graphql und GetPost.generated.ts im selben Verzeichnis. Das verbessert die Nachvollziehbarkeit erheblich, weil Entwickler die generierten Typen einer Query direkt neben der Query selbst finden, statt in einer zentralen, wachsenden Datei zu suchen.
Fuer grosse TypeScript-Projekte mit vielen Teams reduziert dieses Preset ausserdem Merge-Konflikte, weil Aenderungen an unterschiedlichen Queries in unterschiedlichen generierten Dateien landen, statt alle in derselben zentralen Datei zu konkurrieren. Der Umstieg auf dieses Preset lohnt sich meist, sobald ein Projekt mehr als eine Handvoll GraphQL-Operationen umfasst.
| Kriterium | GraphQL Code Generator | Manuelle Typen | tRPC |
|---|---|---|---|
| Synchronitaet mit dem Schema | Automatisch bei jedem Lauf | Nur bei disziplinierter manueller Pflege | Nicht anwendbar, kein Schema |
| Sprachagnostische Konsumenten | Ja, ueber das GraphQL-Schema | Abhaengig von zusaetzlicher Doku | Nein, nur TypeScript-zu-TypeScript |
| Setup-Aufwand | Mittel, Konfigurationsdatei noetig | Keiner zusaetzlich | Niedrig |
| Client-Flexibilitaet | Mehrere Clients ueber Plugins | Beliebig, aber manuell | Eng an den tRPC-Client gebunden |
9. Code Generator im Vergleich zu manuellen Typen und tRPC
Im Vergleich zu manuell gepflegten Typen ist GraphQL Code Generator in praktisch jeder Hinsicht ueberlegen, sobald ein Projekt eine gewisse Groesse erreicht: Der einmalige Konfigurationsaufwand amortisiert sich schnell gegenueber dem wiederkehrenden Risiko vergessener manueller Updates. Im Vergleich zu tRPC bleibt GraphQL mit generierten Typen die bessere Wahl, sobald sprachagnostische Konsumenten wie mobile Apps in nativen Sprachen oder externe Partner-APIs eine Rolle spielen, weil das GraphQL-Schema selbst sprachunabhaengig ist.
Fuer reine TypeScript-zu-TypeScript-Kommunikation innerhalb eines Monorepos kann tRPC hingegen weniger Setup-Aufwand bedeuten, weil kein Schema und kein Codegenerierungs-Schritt noetig sind. Die Entscheidung zwischen beiden Ansaetzen haengt letztlich davon ab, ob ein Projekt die Sprachunabhaengigkeit und Introspektionsfaehigkeit von GraphQL tatsaechlich braucht, oder ob eine reine TypeScript-Umgebung ausreicht.
Mironsoft
TypeScript-GraphQL-Integration, Codegen-Pipelines und API-Architektur
GraphQL-Typen, die manuell gepflegt werden und driften?
Wir richten GraphQL Code Generator fuer euer Schema ein, inklusive typisierter Resolver, typed-document-node fuer Clients und CI-Pruefungen gegen veraltete generierte Dateien.
Codegen-Setup
codegen.yml, Plugin-Auswahl und Near-Operation-File-Struktur
Resolver-Typisierung
Server-Resolver, die garantiert dem deklarierten Schema entsprechen
CI-Integration
Automatische Pruefung auf veraltete generierte Dateien im Build
10. Zusammenfassung
TypeScript mit GraphQL Code Generator loest ein grundlegendes Problem: manuell gepflegte Typen laufen frueher oder spaeter aus dem Schema heraus, waehrend generierte Typen bei jedem Lauf automatisch synchron bleiben. Die codegen.yml-Konfiguration verbindet Schema, Dokumente und Plugins, das Plugin typescript-resolvers garantiert schema-konforme Server-Resolver, und typed-document-node liefert client-uebergreifend typisierte Operationen ohne Bindung an eine bestimmte Bibliothek.
Fuer Teams mit wachsenden GraphQL-Schemas ist die Investition in einen sauberen Code Generator-Workflow, inklusive Watch-Mode fuer die lokale Entwicklung und CI-Pruefung gegen veraltete Dateien, eine der wirksamsten Massnahmen gegen unbemerkte Typ-Inkonsistenzen. Der Vergleich mit manuellen Typen und mit tRPC zeigt: GraphQL Code Generator ist besonders dort im Vorteil, wo Sprachunabhaengigkeit und ein introspektierbares Schema tatsaechlich gebraucht werden.
TypeScript mit GraphQL Code Generator: Das Wichtigste auf einen Blick
codegen.yml als Kern
Schema, Dokumente und Plugin-Liste in einer zentralen Konfigurationsdatei zusammengefuehrt.
typescript-resolvers
Generiert Resolver-Typen, die Server-Implementierung und Schema garantiert synchron halten.
typed-document-node
Client-uebergreifend typisierte Operationen, ohne Bindung an eine bestimmte GraphQL-Bibliothek.
CI-Absicherung
git diff --exit-code nach dem Codegen-Lauf verhindert veraltete, eingecheckte Typen.