🌐 Detecting your location…

So erstellen Sie im Jahr 2026 eine GraphQL-API mit Node.js und Apollo Server

⏱️4 min read  ·  763 words

GraphQL ermöglicht es Kunden, in einer einzigen Anfrage genau die Daten anzufordern, die sie benötigen – kein Über-Abrufen, kein Unter-Abrufen. Kombiniert mitApollo-Server und TypeScript ist es eine leistungsstarke Möglichkeit, flexible APIs zu erstellen. In diesem Leitfaden wird eine vollständige GraphQL-API von Grund auf erstellt.

GraphQL vs. REST – Schnellvergleich

Aspekt RUHE GraphQL
Datenabruf Mehrere Endpunkte Einzelner Endpunkt, präzise Abfragen
Übermäßiges Abrufen Gewöhnlich Eliminiert
Versionierung URL-Versionen (v1, v2) Schemaentwicklung
Am besten für Einfaches CRUD, Caching Komplexe, verschachtelte, kundengesteuerte Daten

Projekt-Setup

mkdir graphql-api && cd graphql-api
npm init -y
npm install @apollo/server graphql
npm install -D typescript tsx @types/node
npx tsc --init

Definieren Sie das Schema

// src/schema.ts
export const typeDefs = `#graphql
  type User {
    id: ID!
    name: String!
    email: String!
    posts: [Post!]!
  }

  type Post {
    id: ID!
    title: String!
    content: String!
    author: User!
    published: Boolean!
  }

  type Query {
    users: [User!]!
    user(id: ID!): User
    posts: [Post!]!
  }

  type Mutation {
    createUser(name: String!, email: String!): User!
    createPost(title: String!, content: String!, authorId: ID!): Post!
    publishPost(id: ID!): Post!
  }
`;

Resolver schreiben

// src/resolvers.ts
import { db } from './db';

export const resolvers = {
  Query: {
    users: () => db.users.findAll(),
    user: (_: any, { id }: { id: string }) => db.users.findById(id),
    posts: () => db.posts.findAll(),
  },

  Mutation: {
    createUser: (_: any, { name, email }: { name: string; email: string }) => {
      return db.users.create({ name, email });
    },
    createPost: (_: any, args: { title: string; content: string; authorId: string }) => {
      return db.posts.create({ ...args, published: false });
    },
    publishPost: (_: any, { id }: { id: string }) => {
      return db.posts.update(id, { published: true });
    },
  },

  // Field resolvers for relationships
  User: {
    posts: (parent: { id: string }) => db.posts.findByAuthor(parent.id),
  },
  Post: {
    author: (parent: { authorId: string }) => db.users.findById(parent.authorId),
  },
};

Erstellen Sie den Server

// src/index.ts
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import { typeDefs } from './schema';
import { resolvers } from './resolvers';

const server = new ApolloServer({ typeDefs, resolvers });

const { url } = await startStandaloneServer(server, {
  listen: { port: 4000 },
  context: async ({ req }) => {
    // Extract auth token, attach user to context
    const token = req.headers.authorization?.replace('Bearer ', '');
    const user = token ? await verifyToken(token) : null;
    return { user };
  },
});

console.log("GraphQL ready at " + url);

Authentifizierung in Resolvern

Mutation: {
  createPost: (_: any, args, context) => {
    // Require authentication
    if (!context.user) {
      throw new GraphQLError('Not authenticated', {
        extensions: { code: 'UNAUTHENTICATED' },
      });
    }
    return db.posts.create({ ...args, authorId: context.user.id });
  },
},

Lösung des N+1-Problems mit DataLoader

Feldauflöser können N+1 Abfragen auslösen (eine Abfrage pro übergeordnetem Element). DataLoader stapelt sie und speichert sie zwischen:

npm install dataloader
import DataLoader from 'dataloader';

// Create a loader that batches user lookups
const userLoader = new DataLoader(async (ids: readonly string[]) => {
  const users = await db.users.findByIds(ids);
  // Return in the same order as requested ids
  return ids.map(id => users.find(u => u.id === id));
});

// Use in resolver — batches all author lookups into one query
Post: {
  author: (parent, _, context) => context.userLoader.load(parent.authorId),
},

Beispielabfrage

# Client requests exactly what it needs
query {
  user(id: "1") {
    name
    posts {
      title
      published
    }
  }
}

# Response contains only requested fields:
# { "data": { "user": { "name": "Alice", "posts": [...] } } }

Häufig gestellte Fragen

F: GraphQL oder REST für mein Projekt?
A: GraphQL für komplexe, verschachtelte, kundengesteuerte Daten (mobile Apps, Dashboards mit unterschiedlichen Anforderungen). REST für einfaches CRUD und wenn HTTP-Caching am wichtigsten ist. Viele Teams nutzen beides.

F: Wie gehe ich mit Datei-Uploads in GraphQL um?
A: Verwenden Sie das graphql-upload-Paket oder laden Sie Dateien besser über einen separaten REST-Endpunkt oder eine vorsignierte URL in den Objektspeicher (S3) hoch und übergeben Sie die URL in Ihrer GraphQL-Mutation.

F: Ist GraphQL schwieriger zwischenzuspeichern als REST?
A: Ja auf HTTP-Ebene (einzelner Endpunkt, POST-Anfragen). Verwenden Sie zum Ausgleich den normalisierten Cache des Apollo-Clients auf dem Client und das persistente Caching von Abfragen oder Antworten auf dem Server.

F: Wie verhindere ich teure/böswillige Anfragen?
A: Fügen Sie eine Begrenzung der Abfragetiefe, eine Komplexitätsanalyse und eine Ratenbegrenzung hinzu. Pakete wie graphql- Depth-Limit und graphql-query-complexity schützen vor tief verschachtelten missbräuchlichen Abfragen.

F: Sollte ich Code-First oder Schema-First verwenden?
A: Schema-first (SDL-Strings, hier gezeigt) ist klar und sprachunabhängig. Code-first (Nexus, TypeGraphQL) sorgt für eine bessere TypeScript-Integration. Beide funktionieren; Wählen Sie je nach Teampräferenz aus.

Fazit

GraphQL mit Apollo Server gibt Kunden eine präzise Kontrolle über die von ihnen abgerufenen Daten und verhindert so Über- und Unterabrufe. Der Aufbau hier – typisiertes Schema, Resolver mit Beziehungen, kontextbasierte Authentifizierung und DataLoader für das N+1-Problem – deckt die Grundlagen einer Produktions-GraphQL-API ab. Fügen Sie Tiefenbegrenzung und Komplexitätsanalyse hinzu, bevor Sie live gehen, und koppeln Sie sie mit Apollo Client, um einen normalisierten Cache im Frontend zu erhalten.

MD Rafikul Islam

Written by

MD Rafikul Islam is a software developer and the editor of TechPulse. He writes about developer tooling, hardware, and the practical decisions that come up in day-to-day engineering work — which laptop to buy, which framework to commit to, why a build broke at 2am. He tests the tools he writes about and says plainly when something is not worth the money. Corrections and corrections requests are welcome at rony.yf25@gmail.com.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা