Rendering the WordPress philosophy in GraphQL

Avatar of Leonardo Losoviz
Leonardo Losoviz am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

WordPress ist ein CMS, das in PHP programmiert ist. Aber obwohl PHP die Grundlage bildet, verfolgt WordPress auch eine Philosophie, bei der die Bedürfnisse der Benutzer über die Bequemlichkeit der Entwickler gestellt werden. Diese Philosophie etabliert einen impliziten Vertrag zwischen den Entwicklern, die WordPress-Themes und Plugins erstellen, und dem Benutzer, der eine WordPress-Website verwaltet.

GraphQL ist eine Schnittstelle, die Daten vom Server abruft – und Daten an diesen übermitteln kann. Ein GraphQL-Server kann seine eigene Meinung darüber haben, wie er die GraphQL-Spezifikation implementiert, um ein bestimmtes Verhalten gegenüber einem anderen zu priorisieren.

Kann die WordPress-Philosophie, die von serverseitiger Architektur abhängt, mit einer JavaScript-basierten Abfragesprache koexistieren, die Daten über eine API übergibt?

Lassen Sie uns diese Frage zerlegen und erklären, wie das von mir verfasste GraphQL API WordPress Plugin eine Brücke zwischen den beiden Architekturen schlägt.

Sie kennen vielleicht WPGraphQL. Das Plugin GraphQL API for WordPress (oder von nun an „GraphQL API“) ist ein anderer GraphQL-Server für WordPress mit anderen Funktionen.

Die WordPress-Philosophie im GraphQL-Dienst wiederherstellen

Diese Tabelle enthält das erwartete Verhalten einer WordPress-Anwendung oder eines Plugins und wie es von einem GraphQL-Dienst, der auf WordPress läuft, interpretiert werden kann.

KategorieErwartetes Verhalten der WordPress-AnwendungInterpretation für den GraphQL-Dienst, der auf WordPress läuft
DatenzugriffDemokratisierung der Veröffentlichung: Jeder Benutzer (unabhängig davon, ob er über technische Fähigkeiten verfügt oder nicht) muss die Software nutzen können.Demokratisierung des Datenzugriffs und der Veröffentlichung: Jeder Benutzer (unabhängig davon, ob er über technische Fähigkeiten verfügt oder nicht) muss das GraphQL-Schema visualisieren und modifizieren sowie eine GraphQL-Abfrage ausführen können.
ErweiterbarkeitDie Anwendung muss durch Plugins erweiterbar sein.Das GraphQL-Schema muss durch Plugins erweiterbar sein.
Dynamisches VerhaltenDas Verhalten der Anwendung kann durch Hooks modifiziert werden.Die Ergebnisse der Auflösung einer Abfrage können durch Direktiven modifiziert werden.
LokalisierungDie Anwendung muss lokalisiert sein, damit sie von Menschen aus jeder Region und jeder Sprache genutzt werden kann.Das GraphQL-Schema muss lokalisiert sein, damit es von Menschen aus jeder Region und jeder Sprache genutzt werden kann.
BenutzeroberflächenDie Installation und Bedienung von Funktionen muss über eine Benutzeroberfläche erfolgen, wobei auf Code so wenig wie möglich zurückgegriffen werden soll.Das Hinzufügen neuer Entitäten (Typen, Felder, Direktiven) zum GraphQL-Schema, deren Konfiguration, die Ausführung von Abfragen und die Festlegung von Berechtigungen für den Zugriff auf den Dienst muss über eine Benutzeroberfläche erfolgen, wobei auf Code so wenig wie möglich zurückgegriffen werden soll.
ZugriffskontrolleDer Zugriff auf Funktionen kann über Benutzerrollen und Berechtigungen gewährt werden.Der Zugriff auf das GraphQL-Schema kann über Benutzerrollen und Berechtigungen gewährt werden.
KonfliktvermeidungEntwickler wissen im Voraus nicht, wer ihre Plugins verwenden wird oder in welcher Konfiguration/Umgebung diese Websites laufen werden. Das bedeutet, dass das Plugin auf Konflikte vorbereitet sein muss (z. B. wenn zwei Plugins denselben SMTP-Dienst definieren) und versuchen muss, diese so weit wie möglich zu vermeiden.Entwickler wissen im Voraus nicht, wer auf das GraphQL-Schema zugreifen und es modifizieren wird oder in welcher Konfiguration/Umgebung diese Websites laufen werden. Das bedeutet, dass das Plugin auf Konflikte vorbereitet sein muss (z. B. wenn zwei Plugins denselben Namen für einen Typ im GraphQL-Schema haben) und versuchen muss, diese so weit wie möglich zu vermeiden.

Sehen wir uns an, wie die GraphQL API diese Ideen umsetzt.

Datenzugriff

Ähnlich wie bei REST muss ein GraphQL-Dienst durch PHP-Funktionen codiert werden. Wer wird das tun und wie?

Änderung des GraphQL-Schemas durch Code

Das GraphQL-Schema umfasst Typen, Felder und Direktiven. Diese werden über Resolver, d. h. PHP-Code-Schnipsel, behandelt. Wer sollte diese Resolver erstellen?

Die beste Strategie ist, dass die GraphQL API das grundlegende GraphQL-Schema mit allen bekannten Entitäten in WordPress (einschließlich Posts, Benutzern, Kommentaren, Kategorien und Tags) bereits bereitstellt und die Einführung neuer Resolver, beispielsweise für Custom Post Types (CPTs), vereinfacht.

So wird die Benutzerentität bereits vom Plugin bereitgestellt. Der User-Typ wird über diesen Code bereitgestellt.

class UserTypeResolver extends AbstractTypeResolver
{
  public function getTypeName(): string
  {
    return 'User';
  }

  public function getSchemaTypeDescription(): ?string
  {
    return __('Representation of a user', 'users');
  }

  public function getID(object $user)
  {
    return $user->ID;
  }

  public function getTypeDataLoaderClass(): string
  {
    return UserTypeDataLoader::class;
  }
}

Der Typ-Resolver lädt die Objekte nicht direkt aus der Datenbank, sondern delegiert diese Aufgabe an ein TypeDataLoader-Objekt (im obigen Beispiel von UserTypeDataLoader). Diese Entkopplung folgt den SOLID-Prinzipien, indem verschiedene Entitäten unterschiedliche Verantwortlichkeiten übernehmen, um den Code wartbar, erweiterbar und verständlich zu machen.

Das Hinzufügen der Felder username, email und url zum User-Typ erfolgt über ein FieldResolver-Objekt.

class UserFieldResolver extends AbstractDBDataFieldResolver
{
  public static function getClassesToAttachTo(): array
  {
    return [
      UserTypeResolver::class,
    ];
  }

  public static function getFieldNamesToResolve(): array
  {
    return [
      'username',
      'email',
      'url',
    ];
  }

  public function getSchemaFieldDescription(
    TypeResolverInterface $typeResolver,
    string $fieldName
  ): ?string {
    $descriptions = [
      'username' => __("User's username handle", "graphql-api"),
      'email' => __("User's email", "graphql-api"),
      'url' => __("URL of the user's profile in the website", "graphql-api"),
    ];
    return $descriptions[$fieldName];
  }

  public function getSchemaFieldType(
    TypeResolverInterface $typeResolver,
    string $fieldName
  ): ?string {
    $types = [
      'username' => SchemaDefinition::TYPE_STRING,
      'email' => SchemaDefinition::TYPE_EMAIL,
      'url' => SchemaDefinition::TYPE_URL,
    ];
    return $types[$fieldName];
  }

  public function resolveValue(
    TypeResolverInterface $typeResolver,
    object $user,
    string $fieldName,
    array $fieldArgs = []
  ) {
    switch ($fieldName) {
      case 'username':
        return $user->user_login;

      case 'email':
        return $user->user_email;

      case 'url':
        return get_author_posts_url($user->ID);
    }

    return null;
  }
}

Wie man sieht, ist die Definition eines Feldes für das GraphQL-Schema und seine Auflösung in eine Vielzahl von Funktionen aufgeteilt.

  • getSchemaFieldDescription
  • getSchemaFieldType
  • resolveValue

Andere Funktionen umfassen

Dieser Code ist lesbarer, als wenn alle Funktionalitäten in einer einzigen Funktion oder über ein Konfigurationsarray abgewickelt würden, was die Implementierung und Wartung der Resolver erleichtert.

Abrufen von Plugin- oder benutzerdefinierten CPT-Daten

Was passiert, wenn ein Plugin seine Daten nicht in das GraphQL-Schema integriert hat, indem es neue Typ- und Feld-Resolver erstellt? Kann der Benutzer dann Daten von diesem Plugin über GraphQL abfragen?

Nehmen wir zum Beispiel an, WooCommerce hat ein CPT für Produkte, führt aber keinen entsprechenden Product-Typ in das GraphQL-Schema ein. Ist es möglich, die Produktdaten abzurufen?

Für CPT-Entitäten können deren Daten über den Typ GenericCustomPost abgerufen werden, der als eine Art Platzhalter dient, um jeden auf der Website installierten benutzerdefinierten Post-Typ abzudecken. Die Einträge werden durch Abfrage von Root.genericCustomPosts(customPostTypes: [cpt1, cpt2, ...]) abgerufen (in dieser Notation für Felder ist Root der Typ und genericCustomPosts das Feld).

Um dann die Produktdaten abzurufen, die dem CPT mit dem Namen "wc_product" entsprechen, führen wir diese Abfrage aus.

{
  genericCustomPosts(customPostTypes: "[wc_product]") {
    id
    title
    url
    date
  }
}

Alle verfügbaren Felder sind jedoch nur die, die in jeder CPT-Entität vorhanden sind: title, url, date usw. Wenn das CPT für ein Produkt Preisdaten enthält, ist kein entsprechendes Feld price verfügbar. wc_product bezieht sich auf ein CPT, das vom WooCommerce-Plugin erstellt wurde. Daher müssen entweder die Entwickler von WooCommerce oder die Website selbst den Product-Typ implementieren und seine eigenen benutzerdefinierten Felder definieren.

CPTs werden häufig zur Verwaltung privater Daten verwendet, die nicht über die API offengelegt werden dürfen. Aus diesem Grund gibt die GraphQL API zunächst nur den Page-Typ frei und erfordert die Angabe, welche anderen CPTs ihre Daten öffentlich abfragen lassen dürfen.

The plugin provides an interface for whitelisting CPTs to be exposed in the API.

Übergang von REST zu GraphQL über persistente Abfragen

Während GraphQL als Plugin bereitgestellt wird, hat WordPress integrierte Unterstützung für REST über die WP REST API. Unter bestimmten Umständen können Entwickler, die mit der WP REST API arbeiten, den Übergang zu GraphQL als problematisch empfinden.

Betrachten wir zum Beispiel diese Unterschiede:

  • Ein REST-Endpunkt hat eine eigene URL und kann über GET abgefragt werden, während GraphQL normalerweise über einen einzigen Endpunkt arbeitet, der nur über POST abgefragt wird.
  • Der REST-Endpunkt kann serverseitig gecached werden (wenn über GET abgefragt), während der GraphQL-Endpunkt normalerweise nicht gecached werden kann.

Folglich bietet REST eine bessere Out-of-the-Box-Unterstützung für Caching, was die Anwendung performanter macht und die Serverlast reduziert. GraphQL hingegen legt mehr Wert auf clientseitiges Caching, wie es vom Apollo Client unterstützt wird.

Muss der Entwickler nach dem Wechsel von REST zu GraphQL die Anwendung auf der Clientseite neu gestalten und den Apollo Client einführen, nur um eine Caching-Schicht zu integrieren? Das wäre bedauerlich.

Die Funktion „persistente Abfragen“ bietet eine Lösung für diese Situation. Persistente Abfragen kombinieren REST und GraphQL und ermöglichen uns:

  • Abfragen mit GraphQL zu erstellen, und
  • die Abfragen unter einer eigenen URL zu veröffentlichen, ähnlich wie bei REST-Endpunkten.

Der persistente Abfrage-Endpunkt verhält sich wie ein REST-Endpunkt: Er kann über GET aufgerufen und serverseitig gecached werden. Er wurde jedoch mit der GraphQL-Syntax erstellt und die exponierten Daten haben kein Under- oder Overfetching.

Erweiterbarkeit

Die Architektur der GraphQL API bestimmt, wie einfach eigene Erweiterungen hinzugefügt werden können.

Entkopplung von Typ- und Feld-Resolvern

Die GraphQL API verwendet das Publish-Subscribe-Muster, damit Felder an Typen „abonniert“ werden.

Betrachten wir den Feld-Resolver von vorhin erneut.

class UserFieldResolver extends AbstractDBDataFieldResolver
{
  public static function getClassesToAttachTo(): array
  {
    return [UserTypeResolver::class];
  }

  public static function getFieldNamesToResolve(): array
  {
    return [
      'username',
      'email',
      'url',
    ];
  }
}

Der User-Typ weiß im Voraus nicht, welche Felder er erfüllen wird, aber diese (username, email und url) werden stattdessen vom Feld-Resolver in den Typ injiziert.

Auf diese Weise wird das GraphQL-Schema leicht erweiterbar. Durch einfaches Hinzufügen eines Feld-Resolvers kann jedes Plugin neue Felder zu einem vorhandenen Typ hinzufügen (z. B. WooCommerce fügt ein Feld für User.shippingAddress hinzu) oder überschreiben, wie ein Feld aufgelöst wird (z. B. User.url neu definieren, um stattdessen die Website des Benutzers zurückzugeben).

Code-First-Ansatz

Plugins müssen in der Lage sein, das GraphQL-Schema zu erweitern. Sie könnten zum Beispiel einen neuen Product-Typ zur Verfügung stellen, ein zusätzliches Feld coauthors zum Post-Typ hinzufügen, eine @sendEmail-Direktive bereitstellen oder etwas anderes tun.

Um dies zu erreichen, folgt die GraphQL API einem Code-First-Ansatz, bei dem das Schema zur Laufzeit aus PHP-Code generiert wird.

Der alternative Ansatz, genannt SDL-First (Schema Definition Language), erfordert, dass das Schema im Voraus bereitgestellt wird, zum Beispiel über eine .gql-Datei.

Der Hauptunterschied zwischen diesen beiden Ansätzen besteht darin, dass im Code-First-Ansatz das GraphQL-Schema dynamisch und an verschiedene Benutzer oder Anwendungen anpassbar ist. Dies passt gut zu WordPress, wo eine einzige Website mehrere Anwendungen (wie Website und mobile App) versorgen und für verschiedene Kunden angepasst werden kann. Die GraphQL API macht dieses Verhalten durch die Funktion „benutzerdefinierte Endpunkte“ explizit, die es ermöglicht, verschiedene Endpunkte mit Zugriff auf unterschiedliche GraphQL-Schemas für verschiedene Benutzer oder Anwendungen zu erstellen.

Um Leistungseinbußen zu vermeiden, wird das Schema durch Caching auf der Festplatte oder im Speicher statisch gemacht und neu generiert, wenn ein neues Plugin, das das Schema erweitert, installiert wird oder wenn der Administrator die Einstellungen aktualisiert.

Unterstützung für neuartige Funktionen

Ein weiterer Vorteil des Code-First-Ansatzes ist, dass er uns ermöglicht, brandneue Funktionen bereitzustellen, die opt-in sind, bevor diese von der GraphQL-Spezifikation unterstützt werden.

Zum Beispiel wurden verschachtelte Mutationen für die Spezifikation angefordert, aber noch nicht genehmigt. Die GraphQL API entspricht der Spezifikation und verwendet die Typen QueryRoot und MutationRoot zur Behandlung von Abfragen und Mutationen, wie im Standard-Schema dargestellt. Durch die Aktivierung der optionalen Funktion „verschachtelte Mutationen“ wird das Schema jedoch transformiert, und sowohl Abfragen als auch Mutationen werden stattdessen von einem einzigen Root-Typ behandelt, was die Unterstützung für verschachtelte Mutationen bietet.

Sehen wir uns diese neuartige Funktion in Aktion an. In dieser Abfrage fragen wir zuerst den Post über Root.post ab, führen dann die Mutation Post.addComment darauf aus und erhalten das erstellte Kommentarobjekt, und führen schließlich die Mutation Comment.reply darauf aus und fragen einige seiner Daten ab (kommentieren Sie die erste Mutation aus, um den Benutzer anzumelden, damit er Kommentare hinzufügen darf).

# mutation {
#   loginUser(
#     usernameOrEmail:"test",
#     password:"pass"
#   ) {
#     id
#     name
#   }
# }
mutation {
  post(id:1459) {
    id
    title
    addComment(comment:"That's really beautiful!") {
      id
      date
      content
      author {
        id
        name
      }
      reply(comment:"Yes, it is!") {
        id
        date
        content
      }
    }
  }
}

Dynamisches Verhalten

WordPress verwendet Hooks (Filter und Aktionen), um das Verhalten zu modifizieren. Hooks sind einfache Code-Schnipsel, die einen Wert überschreiben oder eine benutzerdefinierte Aktion ausführen können, wenn sie ausgelöst werden.

Gibt es ein Äquivalent in GraphQL?

Direktiven zur Überschreibung von Funktionalität

Bei der Suche nach einem ähnlichen Mechanismus für GraphQL bin ich zu dem Schluss gekommen, dass Direktiven bis zu einem gewissen Grad als Äquivalent zu WordPress-Hooks betrachtet werden können: Ähnlich wie ein Filter-Hook ist eine Direktive eine Funktion, die den Wert eines Feldes modifiziert und somit eine andere Funktionalität erweitert.

Nehmen wir zum Beispiel an, wir rufen eine Liste von Post-Titeln mit dieser Abfrage ab.

query {
  posts {
    title
  }
}

…was zu dieser Antwort führt:

{
  "data": {
    "posts": [
      {
        "title": "Scheduled by Leo"
      },
      {
        "title": "COPE with WordPress: Post demo containing plenty of blocks"
      },
      {
        "title": "A lovely tango, not with leo"
      },
      {
      "title": "Hello world!"
      },
    ]
  }
}

Diese Ergebnisse sind in englischer Sprache. Wie können wir sie ins Spanische übersetzen? Mit einer Direktive @translate, die auf das Feld title angewendet wird (implementiert über diesen Direktiven-Resolver), der den Wert des Feldes als Eingabe nimmt, die Google Translate API aufruft, um ihn zu übersetzen, und sein Ergebnis die ursprüngliche Eingabe überschreiben lässt, wie in dieser Abfrage.

query {
  posts {
    title @translate(from:"en", to"es")
  }
}

…was zu dieser Antwort führt:

{
  "data": {
    "posts": [
      {
        "title": "Programado por Leo"
      },
      {
        "title": "COPE con WordPress: publica una demostración que contiene muchos bloques"
      },
      {
        "title": "Un tango lindo, no con leo"
      },
      {
        "title": "¡Hola Mundo!"
      }
    ]
  }
}

Beachten Sie, dass Direktiven nicht davon betroffen sind, wer die Eingabe ist. In diesem Fall war es ein Post.title-Feld, aber es hätte auch Post.excerpt, Comment.content oder jedes andere Feld vom Typ String sein können. Dann sind die Auflösung von Feldern und die Überschreibung ihrer Werte sauber entkoppelt, und Direktiven sind immer wiederverwendbar.

Direktiven zur Verbindung mit Drittanbietern

Da WordPress sich stetig zur „Betriebssystem des Webs“ entwickelt (aktuell 39 % aller Websites, mehr als jede andere Software), nimmt auch die Interaktion mit externen Diensten zu (denken Sie an Stripe für Zahlungen, Slack für Benachrichtigungen, AWS S3 für das Hosting von Assets und andere).

Wie wir oben gesehen haben, können Direktiven verwendet werden, um die Antwort eines Feldes zu überschreiben. Aber woher kommt der neue Wert? Er könnte aus einer lokalen Funktion stammen, aber er könnte auch perfekt von einem externen Dienst stammen (wie bei der Direktive @translate, die wir zuvor gesehen haben und die den neuen Wert von der Google Translate API abruft).

Aus diesem Grund hat die GraphQL API beschlossen, es Direktiven zu erleichtern, mit externen APIs zu kommunizieren, und es diesen Diensten zu ermöglichen, die Daten von der WordPress-Website bei der Ausführung einer Abfrage zu transformieren, z. B. für

  • Übersetzung,
  • Bildkomprimierung,
  • Sourcing über ein CDN und
  • Versand von E-Mails, SMS und Slack-Benachrichtigungen.

Tatsächlich hat die GraphQL API beschlossen, Direktiven so leistungsfähig wie möglich zu machen, indem sie sie zu Low-Level-Komponenten in der Architektur des Servers macht, und sogar die Abfrageauflösung selbst auf einer Direktiven-Pipeline basiert. Dies verleiht Direktiven unter anderem die Befugnis, Autorisierungen, Validierungen und Modifikationen der Antwort durchzuführen.

Lokalisierung

GraphQL-Server, die den SDL-First-Ansatz verwenden, haben Schwierigkeiten, die Informationen im Schema zu lokalisieren (das entsprechende Problem für die Spezifikation wurde vor über vier Jahren erstellt und ist immer noch ungelöst).

Mithilfe des Code-First-Ansatzes kann die GraphQL API jedoch die Beschreibungen auf einfache Weise lokalisieren, über die PHP-Funktion __('some text', 'domain'), und die lokalisierten Zeichenfolgen werden aus einer POT-Datei abgerufen, die der in der WordPress-Administration ausgewählten Region und Sprache entspricht.

Zum Beispiel, wie wir bereits gesehen haben, lokalisiert dieser Code die Feld-Beschreibungen.

class UserFieldResolver extends AbstractDBDataFieldResolver
{
  public function getSchemaFieldDescription(
    TypeResolverInterface $typeResolver,
    string $fieldName
  ): ?string {
    $descriptions = [
      'username' => __("User's username handle", "graphql-api"),
      'email' => __("User's email", "graphql-api"),
      'url' => __("URL of the user's profile in the website", "graphql-api"),
    ];
    return $descriptions[$fieldName];
  }
}

Benutzeroberflächen

Das GraphQL-Ökosystem ist voll von Open-Source-Tools zur Interaktion mit dem Dienst, darunter viele, die das gleiche benutzerfreundliche Erlebnis bieten, das man von WordPress erwartet.

Die Visualisierung des GraphQL-Schemas erfolgt mit GraphQL Voyager.

GraphQL Voyager enables us to interact with the schema, as to get a good grasp of how all entities in the application’s data model relate to each other.

Dies kann besonders nützlich sein, wenn wir eigene CPTs erstellen und überprüfen, wie und woher sie abrufbar sind und welche Daten für sie bereitgestellt werden.

Interacting with the schema

Die Ausführung der Abfrage gegen den GraphQL-Endpunkt erfolgt mit GraphiQL.

GraphiQL for the admin

Dieses Tool ist jedoch nicht für jedermann einfach genug, da der Benutzer Kenntnisse der GraphQL-Abfragesyntax haben muss. Daher wird zusätzlich der GraphiQL Explorer darauf installiert, um die GraphQL-Abfrage durch Klicken auf Felder zusammenzustellen.

GraphiQL with Explorer for the admin

Zugriffskontrolle

WordPress bietet verschiedene Benutzerrollen (Administrator, Redakteur, Autor, Beitragender und Abonnent), um Benutzerberechtigungen zu verwalten, und Benutzer können im wp-admin angemeldet sein (z. B. das Personal), auf der öffentlich zugänglichen Website angemeldet sein (z. B. Kunden) oder nicht angemeldet sein oder kein Konto haben (jeder Besucher). Die GraphQL API muss dies berücksichtigen und den granularen Zugriff für verschiedene Benutzer ermöglichen.

Zugriff auf die Tools gewähren

Die GraphQL API ermöglicht die Konfiguration, wer Zugriff auf die GraphiQL- und Voyager-Clients hat, um das Schema zu visualisieren und Abfragen dagegen auszuführen.

  • Nur der Administrator?
  • Das Personal?
  • Die Kunden?
  • Offen zugänglich für alle?

Aus Sicherheitsgründen bietet das Plugin standardmäßig nur dem Administrator Zugang und exponiert den Dienst nicht offen im Internet.

Auf den Bildern im vorherigen Abschnitt sind die GraphiQL- und Voyager-Clients in wp-admin verfügbar und nur für den Administrator-Benutzer zugänglich. Der Administrator-Benutzer kann Benutzern mit anderen Rollen (Redakteur, Autor, Beitragender) über die Einstellungen Zugriff gewähren.

The admin user can grant access to users with other roles (editor, author, contributor) through the settings.

Um unseren Kunden oder jedem im Internet Zugang zu gewähren, wollen wir ihnen keinen Zugang zum WordPress-Admin geben. Dann ermöglichen die Einstellungen, die Tools unter einer neuen, öffentlich zugänglichen URL (wie z. B. meine-website.com/graphiql und meine-website.com/graphql-interactive) zu exponieren. Das Exponieren dieser öffentlichen URLs ist eine opt-in-Entscheidung, die explizit vom Administrator getroffen wird.

Zugriff auf das GraphQL-Schema gewähren

Die WP REST API macht es nicht einfach, anzupassen, wer Zugriff auf einen bestimmten Endpunkt oder ein Feld innerhalb eines Endpunkts hat, da keine Benutzeroberfläche vorhanden ist und dies über Code erfolgen muss.

Die GraphQL API nutzt stattdessen die Metadaten, die bereits im GraphQL-Schema verfügbar sind, um die Konfiguration des Dienstes über eine Benutzeroberfläche (gestützt durch den WordPress-Editor) zu ermöglichen. Infolgedessen können auch technisch nicht versierte Benutzer ihre APIs verwalten, ohne eine Zeile Code anfassen zu müssen.

Die Verwaltung der Zugriffskontrolle auf die verschiedenen Felder (und Direktiven) des Schemas erfolgt, indem auf sie geklickt und aus einem Dropdown-Menü ausgewählt wird, auf welche Benutzer (wie angemeldete oder solche mit bestimmten Berechtigungen) zugegriffen werden können.

Konflikte verhindern

Namespacing hilft, Konflikte zu vermeiden, wenn zwei Plugins denselben Namen für ihre Typen verwenden. Wenn beispielsweise sowohl WooCommerce als auch Easy Digital Downloads einen Typ namens Product implementieren, wäre es mehrdeutig, eine Abfrage zum Abrufen von Produkten auszuführen. Dann würde Namespacing die Typnamen in WooCommerceProduct und EDDProduct umwandeln und so den Konflikt lösen.

Die Wahrscheinlichkeit, dass ein solcher Konflikt auftritt, ist jedoch nicht sehr hoch. Daher ist die beste Strategie, ihn standardmäßig zu deaktivieren (um das Schema so einfach wie möglich zu halten) und ihn nur bei Bedarf zu aktivieren.

Wenn es aktiviert ist, benennt der GraphQL-Server automatisch Typen anhand des entsprechenden PHP-Paketnamens (für den alle Pakete dem PHP Standard Recommendation PSR-4 folgen). Zum Beispiel für dieses reguläre GraphQL-Schema

Regular GraphQL schema

…mit aktiviertem Namespacing wird Post zu PoPSchema_Posts_Post, Comment zu PoPSchema_Comments_Comment und so weiter.

Namespaced GraphQL schema

Das ist alles, Leute

Sowohl WordPress als auch GraphQL sind an sich fesselnde Themen, daher finde ich die Integration von WordPress und GraphQL sehr reizvoll. Da ich mich nun schon ein paar Jahre damit beschäftige, kann ich sagen, dass die Gestaltung des optimalen Wegs, damit ein altes CMS Inhalte verwaltet und eine neue Schnittstelle darauf zugreift, eine lohnende Herausforderung ist.

Ich könnte noch stundenlang beschreiben, wie die WordPress-Philosophie die Implementierung eines GraphQL-Dienstes unter WordPress beeinflussen kann, und dabei viel Material verwenden, das ich in diesem Artikel nicht aufgenommen habe. Aber ich muss aufhören... Also höre ich jetzt auf.

Ich hoffe, dieser Artikel hat einen guten Überblick über das "Warum" und "Wie" der Befolgung der WordPress-Philosophie in GraphQL gegeben, wie es das Plugin GraphQL API for WordPress tut.