Einleitung
\n\nGraphQL ist eine Abfragesprache für APIs, die es Clients ermöglicht, nur die benötigten Daten abzurufen. In Kombination mit TypeScript wird es zu einem leistungsstarken Werkzeug für die Erstellung typsicherer, skalierbarer und dokumentierter APIs. In diesem Schritt-für-Schritt-Tutorial erstellen wir praktisch eine vollwertige GraphQL API mit TypeScript unter Verwendung von Apollo Server und TypeGraphQL.
Sie werden lernen:
\n- \n
- Wie man ein Projekt mit TypeScript und Apollo Server einrichtet \n
- Wie man ein GraphQL-Schema mit TypeGraphQL-Dekoratoren definiert \n
- Wie man Resolver mit vollständiger Typisierung schreibt \n
- Wie man eine Datenbank anbindet und Abfragen durchführt \n
Dieses Material wird sowohl für Anfänger als auch für Entwickler nützlich sein, die bereits mit REST APIs vertraut sind, aber einen modernen Ansatz zur API-Erstellung erlernen möchten.
\n\n1. Projekteinrichtung und Installation der Abhängigkeiten
\n\nBeginnen wir mit der Initialisierung des Projekts. Stellen Sie sicher, dass Node.js (Version 16+) und npm/yarn installiert sind.
\n\nmkdir graphql-ts-tutorial\ncd graphql-ts-tutorial\nnpm init -y\n\nInstallieren Sie die erforderlichen Pakete:
\n\nnpm install apollo-server graphql reflect-metadata type-graphql class-validator\nnpm install -D typescript @types/node ts-node\n\nErstellen Sie die Datei tsconfig.json:
{\n "compilerOptions": {\n "target": "ES2020",\n "module": "commonjs",\n "lib": ["ES2020"],\n "experimentalDecorators": true,\n "emitDecoratorMetadata": true,\n "strict": true,\n "esModuleInterop": true,\n "outDir": "./dist",\n "rootDir": "./src"\n },\n "include": ["src/**/*"]\n}\n\nBeachten Sie die Flags experimentalDecorators und emitDecoratorMetadata – sie sind für die Arbeit mit TypeGraphQL erforderlich.
2. Definition des Schemas und der Typen mit TypeGraphQL
\n\nErstellen wir den Ordner src und die Datei src/types/User.ts. Hier beschreiben wir das Benutzermodell.
import { ObjectType, Field, ID, InputType } from "type-graphql";\n\n@ObjectType()\nexport class User {\n @Field(() => ID)\n id!: number;\n\n @Field()\n name!: string;\n\n @Field()\n email!: string;\n\n @Field()\n createdAt!: Date;\n}\n\nErklärung:
\n- \n
@ObjectType()– markiert die Klasse als GraphQL-Typ. \n @Field()– gibt an, welche Felder in der API verfügbar sein werden. \n @Field(() => ID)– für den skalaren Typ ID. \n
Jetzt erstellen wir einen InputType für Mutationen (Benutzererstellung):
@InputType()\nexport class CreateUserInput {\n @Field()\n name!: string;\n\n @Field()\n email!: string;\n}\n\nDieser Typ wird in den Resolvern zur Validierung der Eingabedaten verwendet.
\n\n3. Schreiben der Resolver
\n\nErstellen wir die Datei src/resolvers/UserResolver.ts. Hier implementieren wir die Logik für Abfragen und Mutationen.
import { Resolver, Query, Mutation, Arg } from "type-graphql";\nimport { User, CreateUserInput } from "../types/User";\n\n// Simulation einer Datenbank\nlet users: User[] = [\n { id: 1, name: "Ivan Ivanov", email: "ivan@example.com", createdAt: new Date() },\n { id: 2, name: "Maria Petrova", email: "maria@example.com", createdAt: new Date() }\n];\n\nlet nextId = 3;\n\n@Resolver()\nexport class UserResolver {\n @Query(() => [User])\n async users(): Promise<User[]> {\n return users;\n }\n\n @Query(() => User, { nullable: true })\n async user(@Arg("id") id: number): Promise<User | undefined> {\n return users.find(u => u.id === id);\n }\n\n @Mutation(() => User)\n async createUser(@Arg("data") data: CreateUserInput): Promise<User> {\n const newUser: User = {\n id: nextId++,\n name: data.name,\n email: data.email,\n createdAt: new Date()\n };\n users.push(ne