15%

15% auf alle Hosting-Dienste sparen

Teste deine Fähigkeiten und erhalte Rabatt auf jeden Hosting-Plan

Benutze den Code:

Skills
Anfangen
01.11.2024
1 +1

The Complete Guide to GraphQL: Build Faster, Smarter APIs on High-Performance Hosting

GraphQL hat die Art, wie Entwickler APIs entwerfen und nutzen, grundlegend verändert. GraphQL wurde 2012 in Facebooks Engineering-Teams entwickelt und 2015 der Open-Source-Community zur Verfügung gestellt. Seitdem ist GraphQL zu einer der am weitesten verbreiteten API-Abfragesprachen in der modernen Webentwicklung herangewachsen. Egal ob Sie eine Echtzeit-Chat-Anwendung, ein datenintensives Dashboard oder ein mobiles Produkt mit strikten Bandbreitenbeschränkungen entwickeln – GraphQL gibt Ihnen präzise Kontrolle darüber, welche Daten über das Netzwerk übertragen werden.

In diesem umfassenden Leitfaden erfahren Sie, was GraphQL ist, warum es in vielen Szenarien traditionelle REST-APIs übertrifft, wie Sie Ihren ersten GraphQL-Server einrichten und wie Sie ihn auf einer Infrastruktur bereitstellen, die den Anforderungen von Produktionsworkloads gerecht wird.

Inhaltsverzeichnis

  1. Was ist GraphQL?
  2. GraphQL vs. REST: Warum es wichtig ist
  3. Wichtige Funktionen von GraphQL
  4. Einrichten eines GraphQL-Servers
  5. Definieren Ihres Schemas
  6. Implementieren von Resolvern
  7. Abfragen und Mutieren von Daten
  8. Echtzeit-Updates mit Subscriptions
  9. GraphQL-Introspection und Developer Tools
  10. Bereitstellung von GraphQL in der Produktion
  11. Best Practices für Sicherheit
  12. Fazit

1. Was ist GraphQL? {#what-is-graphql}

GraphQL ist eine Open-Source-Abfragesprache für APIs und eine Laufzeitumgebung zum Ausführen dieser Abfragen gegen Ihre Daten. Im Gegensatz zu REST, das einen festen Satz von Endpunkten mit jeweils vordefinierten Datenstrukturen bereitstellt, stellt GraphQL einen einzelnen Endpunkt zur Verfügung, über den Clients genau die Felder und Beziehungen anfordern können, die sie benötigen – nicht mehr, nicht weniger.

Dieser Ansatz beseitigt zwei der hartnäckigsten Probleme beim REST-API-Design:

  • Over-fetching – Empfangen von viel mehr Daten als der Client tatsächlich benötigt, was Bandbreite und Verarbeitungszeit verschwendet.
  • Under-fetching – Empfangen von zu wenig Daten in einer einzelnen Anfrage, was den Client zwingt, mehrere Folgeanfragen zu stellen, um ein vollständiges Bild zusammenzusetzen.

Mit GraphQL bestimmt der Client die Form der Antwort. Der Server erfüllt den durch das Schema definierten Vertrag, und der Client fragt nur das an, das er verwenden möchte.

2. GraphQL vs. REST: Warum es wichtig ist {#graphql-vs-rest}

Zu verstehen, wann GraphQL gegenüber REST zu wählen ist – und umgekehrt – ist entscheidend für fundierte architektonische Entscheidungen.

DimensionRESTGraphQL
EndpunkteMehrere (einer pro Ressource)Einzelner einheitlicher Endpunkt
DatenabrufFeste AntwortstrukturVom Client angegebene Felder
Over-fetchingHäufigVon Grund auf eliminiert
Under-fetchingHäufig (N+1-Problem)Mit verschachtelten Abfragen gelöst
VersionierungURL- oder Header-Versionierung erforderlichSchema-Evolution ohne Versionierung
Echtzeit-UnterstützungErfordert WebSockets oder PollingNative Subscriptions
TypsystemOptional (OpenAPI/Swagger)Integriertes, obligatorisches Schema
CachingHTTP-Level-Caching unkompliziertErfordert abfrage-bewusstes Caching

GraphQL ist besonders leistungsstark für:

  • Komplexe, miteinander verbundene Datenmodelle, bei denen eine einzelne Ansicht Daten aus mehreren Ressourcen erfordert.
  • Mobile Anwendungen, bei denen die Minimierung der Payload-Größe die Benutzererfahrung direkt verbessert und Datenkosten senkt.
  • Schnelle Produktiteration, bei der Frontend-Teams ihre Datenanforderungen weiterentwickeln müssen, ohne auf Backend-API-Änderungen zu warten.
  • Microservices-Aggregation, bei der ein GraphQL-Gateway mehrere nachgelagerte Services zu einer einheitlichen API-Oberfläche zusammenfügt.

REST bleibt eine solide Wahl für einfache CRUD-APIs, öffentliche APIs, die von Dritten genutzt werden und von vorhersehbarer HTTP-Semantik profitieren, sowie Szenarien, bei denen HTTP-Level-Caching eine zwingende Anforderung ist.

3. Wichtige Funktionen von GraphQL {#key-features}

3.1 Präziser Datenabruf

Das definierende Merkmal von GraphQL ist, dass Clients ihre Datenanforderungen in der Abfrage selbst deklarieren. Eine einzelne Anfrage an einen einzelnen Endpunkt kann einen tief verschachtelten Graphen verwandter Objekte abrufen, wobei nur die vom Client angegebenen Felder in der Antwort gefüllt werden.

Dies ist transformativ für Teams, die Produkte auf mehreren Plattformen entwickeln – Web, iOS, Android, Smart TV – wobei jede Oberfläche unterschiedliche Datenanforderungen hat. Anstatt separate REST-Endpunkte zu verwalten oder aufgeblähte Payloads zu akzeptieren, sendet jeder Client eine maßgeschneiderte Abfrage und erhält eine maßgeschneiderte Antwort.

3.2 Stark typisiertes Schema

Jede GraphQL-API wird durch ein Schema unterstützt, das in der GraphQL Schema Definition Language (SDL) geschrieben ist. Das Schema ist der autoritative Vertrag zwischen dem Server und jedem Client, der ihn nutzt. Es definiert:

  • Typen – die Form jedes Objekts in Ihrem Datenmodell.
  • Queries – Lesevorgänge, die Clients ausführen können.
  • Mutations – Schreibvorgänge (erstellen, aktualisieren, löschen).
  • Subscriptions – Echtzeit-Event-Streams.
  • Beziehungen – wie Typen aufeinander verweisen.

Da das Schema stark typisiert ist, werden ganze Kategorien von Bugs zur Entwicklungszeit statt in der Produktion abgefangen. Tooling kann Abfragen gegen das Schema validieren, bevor sie jemals ausgeführt werden, und IDEs können genaue Autovervollständigung und Inline-Dokumentation bereitstellen.

3.3 Echtzeit-Updates mit Subscriptions

Der Subscription-Mechanismus von GraphQL ermöglicht persistente, ereignisgesteuerte Verbindungen zwischen Client und Server – typischerweise über WebSockets implementiert. Wenn ein abonniertes Ereignis auf dem Server auftritt (eine neue Nachricht wird gepostet, ein Aktienkurs ändert sich, ein Bestellstatus wird aktualisiert), sendet der Server die relevanten Daten sofort an alle abonnierten Clients.

Dies macht GraphQL zu einer natürlichen Wahl für:

  • Live-Chat- und Messaging-Anwendungen
  • Collaborative-Editing-Tools
  • Finanz-Dashboards mit Live-Marktdaten
  • Echtzeit-Benachrichtigungen und Activity Feeds
  • Multiplayer-Spielzustand-Synchronisierung

3.4 Introspection

GraphQL-APIs sind von Grund auf selbstdokumentierend. Das Introspection-System ermöglicht es Clients, das Schema selbst abzufragen – verfügbare Typen, Felder, Queries, Mutations und deren Beschreibungen zur Laufzeit zu entdecken. Diese Fähigkeit unterstützt Developer Tools wie GraphiQL und Apollo Studio, die interaktive API-Explorer, Query-Builder und automatische Dokumentationsgenerierung ohne zusätzliche Anstrengung des API-Autors bereitstellen.

3.5 Schema-Evolution ohne Versionierung

Einer der praktischsten Aspekte von GraphQL ist, wie elegant es mit Änderungen umgeht. Da Clients nur die Felder anfordern, die sie benötigen, können Sie neue Felder und Typen zum Schema hinzufügen, ohne bestehende Clients zu unterbrechen. Das Veralten alter Felder wird durch Schema-Anmerkungen statt URL-Versionierung behandelt, wodurch Ihre API-Oberfläche sauber und Ihre Clients stabil bleiben.

4. Einrichten eines GraphQL-Servers {#setting-up}

GraphQL ist sprachunabhängig. Reife Server-Bibliotheken existieren im gesamten Technologie-Stack. Hier sind die am weitesten verbreiteten Optionen:

Sprache / LaufzeitumgebungBibliothek / Framework
Node.jsApollo Server, GraphQL Yoga, Express-GraphQL
PythonStrawberry, Graphene
JavaSpring for GraphQL, graphql-java
Gogqlgen, graphql-go
Rubygraphql-ruby
PHPLighthouse (Laravel), webonyx/graphql-php
Rustasync-graphql
.NET / C#Hot Chocolate, GraphQL.NET

Schritt für Schritt: Node.js mit Apollo Server

Apollo Server ist der am weitesten verbreitete GraphQL-Server im Node.js-Ökosystem. Die folgende Anleitung bringt Sie von Null zu einem laufenden Server.

Voraussetzungen:

  • Node.js 18 oder später installiert
  • npm oder yarn Package Manager

Schritt 1: Initialisieren Sie Ihr Projekt

mkdir graphql-api && cd graphql-api
npm init -y
npm install @apollo/server graphql

Schritt 2: Erstellen Sie Ihre Server-Datei

Erstellen Sie eine Datei namens index.js (oder index.mjs für ES-Module):

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';

// Step 1: Define your type definitions (schema)
const typeDefs = `#graphql
  type Book {
    id: ID!
    title: String!
    author: String!
    publishedYear: Int
    genre: String
  }

  type Query {
    books: [Book!]!
    book(id: ID!): Book
  }
`;

// Step 2: Define your data source (in-memory for this example)
const books = [
  {
    id: '1',
    title: 'The Pragmatic Programmer',
    author: 'David Thomas & Andrew Hunt',
    publishedYear: 1999,
    genre: 'Technology',
  },
  {
    id: '2',
    title: 'Clean Code',
    author: 'Robert C. Martin',
    publishedYear: 2008,
    genre: 'Technology',
  },
];

// Step 3: Define your resolvers
const resolvers = {
  Query: {
    books: () => books,
    book: (_, { id }) => books.find((b) => b.id === id),
  },
};

// Step 4: Create and start the server
const server = new ApolloServer({ typeDefs, resolvers });

const { url } = await startStandaloneServer(server, {
  listen: { port: 4000 },
});

console.log(`🚀 GraphQL server ready at: ${url}`);

Schritt 3: Starten Sie den Server

node index.js
# Output: 🚀 GraphQL server ready at: http://localhost:4000/

Navigieren Sie zu http://localhost:4000/ in Ihrem Browser, um die Apollo Sandbox zu öffnen – einen interaktiven Query-Explorer, in dem Sie Ihre API sofort testen können.

5. Definieren Ihres Schemas {#defining-schema}

Das Schema ist das Rückgrat jeder GraphQL-API. Die Investition von Zeit in ein gut gestaltetes Schema zahlt sich über die gesamte Lebensdauer Ihrer Anwendung aus.

Skalare Typen

GraphQL enthält fünf integrierte skalare Typen:

    Int – 32-Bit-Ganzzahl mit Vorzeichen
    Float – Gleitkommazahl mit doppelter Genauigkeit
    String – UTF-8-Zeichenfolge
    Boolean – true oder false
  • ID – eindeutige Kennung, serialisiert als Zeichenfolge
  • Sie können auch benutzerdefinierte Skalare für Typen wie Date, DateTime, Email, URL oder JSON definieren.

    Objekttypen

    type Author {
      id: ID!
      name: String!
      biography: String
      books: [Book!]!
    }
    
    type Book {
      id: ID!
      title: String!
      author: Author!
      publishedYear: Int
      genre: String
      tags: [String!]
    }

    Der !-Modifizierer kennzeichnet ein nicht-nullbares Feld. [Book!]! bedeutet eine nicht-nullbare Liste von nicht-nullbaren Book-Objekten.

    Queries

    type Query {
      books: [Book!]!
      book(id: ID!): Book
      authors: [Author!]!
      author(id: ID!): Author
      booksByGenre(genre: String!): [Book!]!
    }

    Mutations

    type Mutation {
      createBook(title: String!, authorId: ID!, genre: String): Book!
      updateBook(id: ID!, title: String, genre: String): Book
      deleteBook(id: ID!): Boolean!
    }

    Input-Typen

    Für Mutations mit mehreren Argumenten halten Input-Typen Ihr Schema sauber und wiederverwendbar:

    input CreateBookInput {
      title: String!
      authorId: ID!
      publishedYear: Int
      genre: String
      tags: [String!]
    }
    
    type Mutation {
      createBook(input: CreateBookInput!): Book!
    }

    6. Implementieren von Resolvern {#implementing-resolvers}

    Resolver sind die Funktionen, die jedes Feld in Ihrem Schema erfüllen. Jedes Feld in einem GraphQL-Schema kann einen Resolver haben. Wenn kein Resolver für ein Feld definiert ist, greift GraphQL auf einen Standard-Resolver zurück, der einfach die Eigenschaft mit dem gleichen Namen vom übergeordneten Objekt zurückgibt.

    Resolver-Signatur

    fieldName: (parent, args, context, info) => value
    • parent – der aufgelöste Wert des übergeordneten Typs (nützlich für verschachtelte Resolver).
    • args – die an das Feld in der Abfrage übergebenen Argumente.
    • context – ein gemeinsames Objekt, das durch die gesamte Resolver-Kette übergeben wird, typischerweise enthält es den authentifizierten Benutzer, die Datenbankverbindung oder Daten-Loader.
    • info – Metadaten über die Abfrageausführung, einschließlich des Feldnamens und des Schemas.

    Beispiel: Resolver mit einer Datenbank

    const resolvers = {
      Query: {
        books: async (_, __, { db }) => {
          return db.collection('books').find().toArray();
        },
        book: async (_, { id }, { db }) => {
          return db.collection('books').findOne({ _id: id });
        },
      },
    
      Mutation: {
        createBook: async (_, { input }, { db, user }) => {
          if (!user) throw new Error('Authentication required');
          const result = await db.collection('books').insertOne(input);
          return { id: result.insertedId, ...input };
        },
      },
    
      Book: {
        // Nested resolver: fetch the author for each book
        author: async (book, _, { db }) => {
          return db.collection('authors').findOne({ _id: book.authorId });
        },
      },
    };

    Vermeidung des N+1-Problems mit DataLoader

    Verschachtelte Resolver können das N+1-Abfrage-Problem auslösen – Abrufen einer Liste von 100 Büchern und dann Durchführen von 100 separaten Datenbankaufrufen zum Auflösen des Autors jedes Buches. Die Lösung ist DataLoader, ein Batching- und Caching-Dienstprogramm:

    import DataLoader from 'dataloader';
    
    // In your context factory:
    const authorLoader = new DataLoader(async (authorIds) => {
      const authors = await db.collection('authors')
        .find({ _id: { $in: authorIds } })
        .toArray();
      return authorIds.map((id) => authors.find((a) => a._id === id));
    });
    
    // In your resolver:
    Book: {
      author: (book, _, { authorLoader }) => authorLoader.load(book.authorId),
    }

    DataLoader batched alle author-Lookups innerhalb eines einzelnen Ticks der Event-Schleife in eine einzelne Datenbankabfrage, wodurch 100 Abfragen auf 1 reduziert werden.

    7. Abfragen und Mutieren von Daten {#querying-data}

    Grundlegende Abfrage

    query GetAllBooks {
      books {
        id
        title
        author {
          name
        }
        genre
      }
    }

    Abfrage mit Argumenten

    query GetBook {
      book(id: "1") {
        title
        author {
          name
          biography
        }
        publishedYear
        tags
      }
    }

    Abfrage mit Variablen

    Variablen halten Ihre Abfragen dynamisch und verhindern Injection-Anfälligkeit:

    query GetBook($bookId: ID!) {
      book(id: $bookId) {
        title
        author {
          name
        }
      }
    }
    {
      "bookId": "1"
    }

    Mutations-Beispiel

    mutation AddBook($input: CreateBookInput!) {
      createBook(input: $input) {
        id
        title
        author {
          name
        }
      }
    }
    {
      "input": {
        "title": "Designing Data-Intensive Applications",
        "authorId": "42",
        "publishedYear": 2017,
        "genre": "Technology"
      }
    }

    Fragmente

    Fragmente ermöglichen es Ihnen, Feldauswahlen über mehrere Abfragen hinweg wiederzuverwenden:

    fragment BookDetails on Book {
      id
      title
      genre
      publishedYear
    }
    
    query {
      books {
        ...BookDetails
        author {
          name
        }
      }
    }

    8. Echtzeit-Updates mit Subscriptions {#subscriptions}

    GraphQL-Subscriptions unterhalten eine persistente Verbindung – typischerweise über WebSockets – und pushen Daten an Clients, wenn bestimmte Ereignisse auf dem Server auftreten.

    Schema-Definition

    type Subscription {
      bookAdded: Book!
      bookUpdated(id: ID!): Book!
    }

    Server-Implementierung (Apollo Server mit WebSockets)

    npm install graphql-ws ws @graphql-tools/schema
    import { createServer } from 'http';
    import { WebSocketServer } from 'ws';
    import { useServer } from 'graphql-ws/lib/use/ws';
    import { makeExecutableSchema } from '@graphql-tools/schema';
    import { PubSub } from 'graphql-subscriptions';
    
    const pubsub = new PubSub();
    
    const resolvers = {
      Mutation: {
        createBook: async (_, { input }, { db }) => {
          const book = await db.collection('books').insertOne(input);
          pubsub.publish('BOOK_ADDED', { bookAdded: book });
          return book;
        },
      },
      Subscription: {
        bookAdded: {
          subscribe: () => pubsub.asyncIterator(['BOOK_ADDED']),
        },
      },
    };
    
    const schema = makeExecutableSchema({ typeDefs, resolvers });
    const httpServer = createServer();
    const wsServer = new WebSocketServer({ server: httpServer, path: '/graphql' });
    useServer({ schema }, wsServer);

    Client-Subscription

    subscription OnBookAdded {
      bookAdded {
        id
        title
        author {
          name
        }
      }
    }

    9. GraphQL-Introspection und Developer Tools {#introspection}

    Das Introspection-System von GraphQL ist eines seiner entwicklerfreundlichsten Features. Durch Abfragen der Meta-Felder __schema und __type können Clients und Tools die vollständige Struktur Ihrer API zur Laufzeit entdecken.

    Introspection-Abfrage-Beispiel

    {
      __schema {
        types {
          name
          kind
          description
        }
      }
    }

    Wesentliche Developer Tools

    ToolZweck
    GraphiQLIn-Browser-IDE zum Schreiben und Testen von Abfragen
    Apollo StudioVollständiges API-Management, Performance-Monitoring, Schema-Registry
    PostmanGraphQL-Abfrage-Unterstützung mit Collection-Management
    InsomniaLeichter API-Client mit GraphQL-Unterstützung
    GraphQL Code GeneratorGeneriert automatisch TypeScript-Typen aus Ihrem Schema
    Apollo Client DevToolsBrowser-Erweiterung zum Debuggen des Apollo Client Cache

    > Sicherheitshinweis: Deaktivieren Sie Introspection in Produktionsumgebungen, um zu vermeiden, dass Ihr API-Schema potenziellen Angreifern ausgesetzt wird. Apollo Server macht dies unkompliziert:

    >

    > “`javascript

    > new ApolloServer({ typeDefs, resolvers, introspection: false });

    > “`

    10. Bereitstellung von GraphQL in der Produktion {#deploying}

    Das Verschieben einer GraphQL-API von der Entwicklung in die Produktion erfordert sorgfältige Aufmerksamkeit auf Infrastruktur, Performance und Zuverlässigkeit.

    Wahl der richtigen Hosting-Infrastruktur

    Die Infrastruktur, auf der Sie Ihre GraphQL-API ausführen, wirkt sich direkt auf ihre Performance, Zuverlässigkeit und Skalierbarkeit aus. Für Produktionsworkloads haben Sie mehrere starke Optionen:

    VPS-Hosting ist ein ausgezeichneter Ausgangspunkt für die meisten GraphQL-APIs. Ein VPS-Hosting-Plan gibt Ihnen dedizierte Ressourcen, Root-Zugriff und die Freiheit, Ihre Node.js-Laufzeitumgebung, Ihren Reverse Proxy und Ihren Process Manager genau nach Ihren Anforderungen zu konfigurieren. AlexHost VPS-Pläne sind für performance-sensitive Workloads konzipiert und enthalten SSD-Speicher und hochperformante Konnektivität.

    Dedicated Server sind die richtige Wahl, wenn Ihre GraphQL-API hohe Abfragevolumina, komplexe Subscription-Workloads verarbeitet oder als Gateway mehrere Microservices aggregiert. Mit einem Dedicated Server erhalten Sie exklusiven Zugriff auf alle CPU-, RAM- und I/O-Ressourcen – keine lauten Nachbarn, keine Ressourcenkonflikte und die rohe Leistung, um Tausende gleichzeitiger WebSocket-Verbindungen für Subscriptions zu verarbeiten.

    GPU-Hosting ist einen Überlegung wert, wenn Ihre GraphQL-API als Interface-Layer für Machine-Learning-Inferenz, Echtzeit-Datenverarbeitungspipelines oder KI-gestützte Features dient. GPU-Hosting von AlexHost stellt Ihnen NVIDIA GPU-Ressourcen zur Verfügung und ermöglicht es Ihrer API, rechenintensive Ergebnisse mit niedriger Latenz bereitzustellen.

    Production Deployment Stack

    Eine robuste Produktionsbereitstellung für eine GraphQL-API sieht typischerweise so aus:

    Client → CDN / Load Balancer → Nginx (Reverse Proxy) → Node.js (PM2) → Database
                                                          ↘ Redis (Caching / PubSub)

    Schritt 1: Installieren und konfigurieren Sie Nginx als Reverse Proxy

    server {
        listen 80;
        server_name api.yourdomain.com;
    
        location /graphql {
            proxy_pass http://localhost:4000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_cache_bypass $http_upgrade;
        }
    }

    Die Header Upgrade und Connection sind entscheidend für WebSocket-Unterstützung, die GraphQL-Subscriptions unterstützt.

    Schritt 2: Verwalten Sie Ihren Node.js-Prozess mit PM2

    npm install -g pm2
    pm2 start index.js --name graphql-api --instances max
    pm2 save
    pm2 startup

    --instances max aktiviert den Cluster-Modus und erzeugt einen Worker-Prozess pro CPU-Kern, um den Durchsatz zu maximieren.

    Schritt 3: Sichern Sie mit SSL

    Jede Produktions-API muss über HTTPS bereitgestellt werden. Ein SSL-Zertifikat von AlexHost stellt sicher, dass alle Daten in Transit zwischen Clients und Ihrem GraphQL-Endpunkt verschlüsselt sind. Dies ist besonders wichtig für APIs, die Authentifizierungstoken, persönliche Daten oder Finanzinformationen verarbeiten.

    # Install Certbot and obtain a certificate
    sudo apt install certbot python3-certbot-nginx
    sudo certbot --nginx -d api.yourdomain.com

    Schritt 4: Registrieren Sie Ihre Domain

    Ihre API benötigt eine einprägsame, professionelle Domain. Domain-Registrierung über AlexHost gibt Ihnen Zugriff auf alle wichtigen TLDs mit unkompliziertem DNS-Management, was es einfach macht, Ihre Domain auf Ihren Server zu verweisen und Subdomains für Staging- und Produktionsumgebungen zu konfigurieren.

    Caching-Strategien

    Das Single-Endpoint-Modell von GraphQL bedeutet, dass HTTP-Level-Caching (das auf URL-Differenzierung beruht) nicht sofort funktioniert. Verwenden Sie stattdessen diese Strategien:

    • Persisted Queries – Clients senden einen Hash der Abfrage statt der vollständigen Abfragezeichenfolge, was CDN-Caching nach Hash ermöglicht.
    • Response Caching – Cache-Resolver-Ergebnisse in Redis basierend auf Abfrage-Hash und
    15%

    15% auf alle Hosting-Dienste sparen

    Teste deine Fähigkeiten und erhalte Rabatt auf jeden Hosting-Plan

    Benutze den Code:

    Skills
    Anfangen