Ressourcen
RessourcenBest practice GraphQL

Best practice GraphQL

GraphQL ist ausgereift genug und existiert schon lange genug, sodass die Community zahlreiche Artikel über Best Practices veröffentlicht hat. Diese Anleitungen decken praktisch alle Aspekte von GraphQL ab, darunter Schema-Design, Namenskonventionen, Sicherheitshandhabung und das Bereitstellen aussagekräftiger Fehlermeldungen.

Hier sind einige der überzeugendsten Anleitungen zu Best Practices in GraphQL.

Best Practices auf graphql.org

Die offizielle GraphQL-Website bietet eine allgemeine Einführung in die Best Practices in GraphQL.

Diese Punkte behandeln hauptsächlich übergeordnete Themen, wie:

Wo der GraphQL-Layer innerhalb der Architektur positioniert ist

Lee Byrons Empfehlungen

Kurz nach der Veröffentlichung von GraphQL veröffentlichte GraphQL-Erfinder Lee Byron den Artikel Lessons From 4 Years of GraphQL, in dem er beschreibt, wie wir konzeptionell mit GraphQL arbeiten sollten:

  • Naming ist wichtig
  • Denke in Graphen, nicht in Endpunkten
  • Beschreibe die Daten, nicht die Ansicht
  • GraphQL ist ein schlankes Interface
  • Verstecke Implementierungsdetails

Er beschreibt außerdem mehrere wertvolle Prinzipien und Lektionen, die er beim Einsatz von GraphQL bei Facebook gelernt hat.

GraphQL Rules

GraphQL Rules ist eine Website, die sich speziell der Präsentation von alltäglichen Best Practices für die Arbeit mit GraphQL widmet und sich hauptsächlich auf das Design des GraphQL-Schemas konzentriert.

Diese Ressource ist sehr umfassend. Sie fasst die Informationen aus einigen außergewöhnlichen Quellen zusammen (wie dem Artikel Designing GraphQL Mutations und dem Shopify-Tutorial Designing a GraphQL API) und präsentiert sie alle zusammen in prägnanter Form.

Die beschriebenen Regeln umfassen:

  1. Benennungsregeln
    • Verwende camelCase für GraphQL-Felder und Argumente.
    • Verwende UpperCamelCase für GraphQL-Typen.
    • Verwende CAPITALIZED_WITH_UNDERSCORES zum Benennen von ENUM-Typen.
  2. Typregeln
    • Verwende benutzerdefinierte Skalartypen, wenn du Felder oder Argumente mit einem bestimmten semantischen Wert deklarieren möchtest.
    • Verwende Enum für Felder, die eine bestimmte Menge von Werten enthalten.
  3. Feldregeln (Output)
    • Verwende semantische Namen für Felder und vermeide das Durchsickern von Implementierungsdetails in Feldnamen.
    • Verwende ein Non-Null-Feld, wenn ein Feld immer einen bestimmten Wert hat.
    • Gruppiere so viele verwandte Felder wie möglich in einem benutzerdefinierten Object-Typ.
  4. Argumentregeln (Input)
    • Gruppiere zusammengehörige Argumente in einem neuen Input-Typ.
    • Verwende strikte Skalartypen für Argumente, z. B. DateTime statt String.
    • Markiere Argumente als required, wenn sie für die Ausführung der query erforderlich sind.
  5. Listenregeln
    • Verwende zum Filtern von Listen das Argument filter, das alle verfügbaren Filter enthält.
    • Verwende das Argument sort vom Typ Enum oder [Enum!] zum Sortieren von Listings.
    • Verwende limit mit einem Standardwert und skip, um die Anzahl der zurückgegebenen Elemente in einer Liste zu begrenzen.
    • Verwende die Argumente page, perPage für die Paginierung und gib einen Output-Typ mit items (Array von Elementen) und pageInfo (Metadaten) zurück.
    • Für unendliche Listen (Infinite Scroll) verwende die Relay Cursor Connections Specification.
  6. Mutation-Regeln
    • Verwende Namespace-Typen, um Mutations innerhalb einer einzelnen Ressource zu gruppieren.
    • Gehe über CRUD hinaus – erstelle kleine Mutations für verschiedene Geschäftsoperationen auf Ressourcen.
    • Berücksichtige die Möglichkeit, Mutations auf mehreren Elementen auszuführen (Batch-Änderungen desselben Typs).
    • Mutations sollten alle Pflichtargumente klar beschreiben, es sollte keine Entweder-oder-Optionen geben.
    • Füge bei Mutations alle Variablen in ein einziges eindeutiges Input-Argument ein.
    • Jede Mutation sollte einen eindeutigen Payload-Typ haben.

Best Practices für Resolver

Der Artikel GraphQL Resolvers: Best Practices beschreibt, wie man Feld-Resolver am besten erstellt. Obwohl er sich an Node.js-Server richtet (PayPals Infrastruktur basiert auf Express), können einige seiner Lektionen auch auf andere Technologien angewendet werden, einschließlich PHP.

Die wichtigsten Erkenntnisse sind:

  • Das Abrufen und Weitergeben von Daten von Eltern zu Kindern sollte sparsam eingesetzt werden.
  • Verwende Bibliotheken wie dataloader, um doppelte Downstream-Anfragen zu vermeiden.
  • Sei dir bewusst, welchen Druck du auf deine Datenquellen ausübst.
  • Mutiere "context" nicht. Das sorgt für konsistenten, weniger fehleranfälligen Code.
  • Schreibe Resolver, die lesbar, wartbar und testbar sind. Nicht zu clever.
  • Mache deine Resolver so schlank wie möglich. Extrahiere die Datenabruf-Logik in wiederverwendbare async-Funktionen.

OWASP - GraphQL Cheat Sheet

OWASP (Open Web Application Security Project) ist eine gemeinnützige Stiftung, die daran arbeitet, die Sicherheit von Software zu verbessern. Sie forscht daran, wie verschiedene Technologien für Exploits anfällig sind, und beschreibt detailliert Lösungen für Sicherheitsprobleme, sodass es für Entwickler einfacher wird, Angriffe zu verhindern.

OWASP hat das GraphQL Cheat Sheet veröffentlicht, das erklärt, welche die häufigsten Angriffe und größten Sicherheitsprobleme in GraphQL sind und wie man sie behebt.

Häufige Angriffe auf GraphQL sind:

  1. Injection – dazu gehören in der Regel, aber nicht ausschließlich:
    • SQL- und NoSQL-Injection
    • OS-Command-Injection
    • SSRF- und CRLF-Injection / Request Smuggling
  2. DoS (Denial of Service)
  3. Missbrauch von defekter Autorisierung: unangemessener oder übermäßiger Zugriff, einschließlich IDOR
  4. Batching Attacks, eine GraphQL-spezifische Methode von Brute-Force-Angriffen
  5. Missbrauch unsicherer Standardkonfigurationen

OWASP gibt dann Empfehlungen, wie jede dieser Situationen vermieden werden kann.

Best Practices mit GraphQL-queries

Das Apollo-Team hat die GraphQL query best practices veröffentlicht und gibt praktische Einblicke, wie man GraphQL-queries zusammenstellt.

Diese beiden queries erreichen zum Beispiel dasselbe Ziel, aber da die erste einen Operationsnamen hat, ist sie verständlicher und beim Debugging hilfreicher:

# Consigliato ✅
query GetBooks {
  books {
    title
  }
}
 
# Non consigliato ❌
query {
  books {
    title
  }
}

Ihre Vorschläge umfassen:

  • Alle Operationen benennen
  • Variablen verwenden, um GraphQL-Argumente bereitzustellen
  • Nur die Daten abfragen, die du brauchst, dort wo du sie brauchst
  • Fragments verwenden, um zusammengehörige Feldmengen zu kapseln
  • Globale Daten und benutzerspezifische Daten separat abfragen

Den One Graph nutzen

Ebenfalls vom Apollo-Team stammt die Website Principled GraphQL, die erklärt, dass GraphQL nicht nur eine Spezifikation ist, sondern – möglicherweise noch wichtiger – ein Interface zur Interaktion mit dem Daten-"Graph" unseres Unternehmens.

Anhand einer Liste von 10 Prinzipien beschreibt diese Website, wie man das Beste aus dem einzelnen Graph herausholt:

  1. One Graph: Dein Unternehmen sollte einen einheitlichen Graph haben, anstatt mehrerer Graphen, die von jedem Team erstellt werden.
  2. Federated Implementation: Obwohl es nur einen Graph gibt, sollte die Implementierung dieses Graphs über mehrere Teams federiert werden.
  3. Track the Schema in a Registry: Es sollte eine einzige Quelle der Wahrheit für die Registrierung und Nachverfolgung des Graphs geben.
  4. Abstract, Demand-Oriented Schema: Das Schema sollte als Abstraktionsschicht fungieren, die Konsumenten Flexibilität bietet und gleichzeitig Implementierungsdetails des Services verbirgt.
  5. Use an Agile Approach to Schema Development: Das Schema sollte schrittweise basierend auf tatsächlichen Anforderungen aufgebaut werden und sich mit der Zeit reibungslos weiterentwickeln.
  6. Iteratively Improve Performance: Das Performance-Management sollte ein kontinuierlicher, datengesteuerter Prozess sein, der sich reibungslos an sich ändernde Query-Lasten und Service-Implementierungen anpasst.
  7. Use Graph Metadata to Empower Developers: Entwickler sollten während des gesamten Entwicklungsprozesses mit einem umfassenden Bewusstsein für den Graph ausgestattet sein.
  8. Access and Demand Control: Gewähre den Zugriff auf den Graph auf Client-Basis und verwalte, was und wie Clients darauf zugreifen können.
  9. Structured Logging: Erfasse strukturierte Logs aller Graph-Operationen und nutze sie als primäres Werkzeug zum Verständnis der Graph-Nutzung.
  10. Separate the GraphQL Layer from the Service Layer: Übernimm eine mehrschichtige Architektur, bei der die Graph-Funktionalität in eine separate Schicht aufgeteilt wird, anstatt in jeden Service integriert zu sein.