PostGraphile: Von der Datenbank-Tabelle zu Queries & Mutations

Ihr habt es ja sicherlich schon mitbekommen: Aktuell wollen wir euch in einer Serie von Blogposts PostGraphile näher bringen. Dazu gehörte bisher eine ganze Reihe an Vorbereitung – doch jetzt wollen wir mal richtig loslegen.

Denn in diesem Artikel beleuchten wir, was PostGraphile uns schon out of the Box bietet, wenn wir unser Datenbank-Schema definiert haben. Alle Beispiele und ein docker-compose-Setup zum Spielen findet ihr in unserem GitHub-Repository zur Serie.

GraphiQL

GraphiQL ist ein Web IDE für GraphQL, der in den meisten GraphQL-Bibliotheken für verschiedene Programmiersprachen schon mit ausgeliefert wird.

Es bietet die Möglichkeit, das GraphQL-Schema zu inspizieren, Queries zu erstellen1,2, zu testen3 und wenn nötig zu debuggen4. GraphQL-Queries können sowohl links im „Explorer“ grafisch 1 oder im Editor textuell 2 definiert werden.

Das UI unterstützt, indem es Vorschläge für Felder macht und auch anzeigt, wenn es ein Feld nicht gibt. Diese Informationen werden über einen Introspection Query bezogen. Im rechten Abschnitt5 kann das Schema angeschaut und nach Feldern oder Typen gesucht werden.

Wenn die Option Enhanced GraphiQL aktiviert ist, können auch SQL Explains4  für den GraphQL-Query mitgeliefert werden. Das ist sehr nützlich für das Debuggen von langsamen Anfragen.

Für die Produktionsumgebung sollte GraphiQL und Schema Introspection allerdings nicht aktiv sein, wenn es sich um ein nicht öffentliches API handelt. Zum Einen werden Kommentare an Feldern mit ausgeliefert, die eventuell nicht öffentlich sein sollen, und zum Anderen wird es dem Angreifer potenziell einfacher gemacht, Schwachstellen zu finden. Letzteres ist nur ein sehr schwaches Argument, denn es handelt sich um Security by Obscurity. Aber warum sollte man es Angreifern leicht machen?

GraphiQL

Was generiert PostGraphile aus einer Tabelle?

Für unser Beispiel verwenden wir eine rudimentäre Blogpost-Verwaltung mit folgendem Entity-Relation-Model.

Zusätzlich existiert noch ein eigener Enum-Typ Namens BLOGPOST_ENUM mit den werten ‚Technical‘ und ‘Agile‘. Nun schauen wir uns an, was PostGraphile aus dem Datenbank-Schema alles generiert.

PostGraphile gruppiert alle nicht mutierenden Felder unter Query und alle mutierenden Felder unter Mutation. Wir schauen uns im Einzelnen genauer an, was generiert wird.

Query

Wenn wir uns das Schema für unseren Query-Root-Typ in GraphQL Voyager visualisieren lassen, können wir relativ einfach die Typen und Beziehungen in unserem Schema erkennen.

Mit allBlogposts / allWriters können wir mehrere Entitäten selektieren, wobei es sich um eine Connection handelt. Was das ist, wird im Folgenden noch erläutert.

Besonders ist, dass wir unter nodes die Felder definieren müssen, die wir brauchen. Mit blogpostById / writerById können wir uns eine Entität anhand der Datenbank-ID selektieren.

Mit blogpost / writer können wir uns eine Entität anhand der NodeId selektieren. Auch die NodeId wird im Folgenden noch genauer erläutert.

Mutation

Das gleiche Schema für den Mutation-Typ sieht schon sehr viel komplexer aus, da für Mutationen noch ein Payload-Typ generiert wird.

Mit createBlogpost / createWriter lassen sich neue Entitäten anlegen. Hierbei müssen im Input-Argument die zu schreibenden Felder übergeben werden.

Mit deleteBlogpost / updateBlogpostById und deleteWriter / updateWriterById können Entitäten anhand der NodeId bzw. des Primary Key (PK) gelöscht werden.

Mit deleteBlogpost / updateBlogpostById und deleteWriter / updateWriterById können Entitäten anhand der NodeId bzw. des PK modifiziert werden. Hierbei wird ein Patch übergeben, in dem die Felder angegeben werden, die geändert werden sollen.

Bei allen Mutationen gilt, dass auch gleichzeitig Daten selektiert werden können, und es muss immer mindestens ein Feld zurückgegeben werden.

Typen

PostGraphile versucht, die Typen so genau wie möglich abzubilden. Es berücksichtigt Felder in der Datenbank, die mit „NOT NULL“ angelegt wurden, z. B. name im Writer-Typ ist vom Typ String!, wohingegen nickname vom Typ String ist, weil es in der Datenbank nicht mit „NOT NULL“ angelegt wurde. Das Ausrufezeichen wird also genutzt, um „Pflichtfelder“ zu kennzeichnen.

Da es in PostgreSQL möglich ist eigene Typen zu definieren, hat PostGraphile auch die Fähigkeit, diese Typen in dem resultierenden GraphQL-Schema aufzunehmen. So hat z. B. der Typ Blogpost ein Feld blogpostType der vom Typ BlogpostEnum ist, was in der Datenbank auch so abgebildet ist. Damit ist es möglich, seine Daten so konsistent wie möglich abzubilden – und dies ohne den zusätzlichen Aufwand, das auch im API zu reflektieren.

Connection

Bei Feldern, die den Connection-Typ implementieren, können wir Filter, Sortierung, und Pagination einstellen. Das sind Felder, die mit all beginnen, z. B. allWriters, und im Query-Feld abgefragt werden können. Oder aber Felder, die Entitäten-Beziehungen darstellen, also 1:N sind.

Eine genauere Erläuterung der Felder kann in dieser Dokumentation nachgeschlagen werden.

Primary Keys & NodeId

Jede Entität, die einen PK hat, hat auch automatisch eine NodeId. Dies kann auch ein zusammengesetzter PK sein.

Die NodeId ist ein Base64-encoded Json-Array, das als erstes Element den Tabellenamen hat und bei dem alle weiteren Elemente die PKs der Tabelle sind. Beispielsweise wäre die decodierte NodeId des ersten Blogposts ["blogposts",1].

NodeIds können für das Entitäten-basierte clientseitige Caching verwendet werden, weswegen sie auch immer mit selektiert werden sollten.

Foreign Keys

Die Besonderheit an GraphQL ist, dass die Beziehungen zwischen den Entitäten abgebildet werden. Wenn wir uns zum Beispiel den Typ Writer anschauen, existiert in diesem ein Feld blogpostsByWriterId, mit dem Blogposts zu diesem Writer selektiert werden können. Das Feld hat den selben Aufbau wie allBlogposts, mit dem Unterschied, dass sich das Feld nur auf diesen einen Writer bezieht.

Ohne Plug-ins werden nur 1:1- und 1:n-Beziehungen unterstützt. Allerdings gibt es auch Plug-ins, die N:M-Beziehungen vereinfacht abbilden können.

PostGraphile in-depth



Und nun?

In diesem Artikel habe ich euch gezeigt, was PostGraphile out of the box liefert und wie euch GraphiQL das Leben leichter macht. Außerdem haben wir euch ein docker-compose-Setup zum Spielen zur Verfügung gestellt.

Im nächsten Teilen der Serie behandeln wir die Möglichkeiten, die PostGraphile-Generierung und das GraphQL-Schema nach euren Bedürfnissen anzupassen oder zu erweitern.

Für neue Blogupdates anmelden:


Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.