🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

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.

✍️ Leave a Comment

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

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