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?
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.
Schreibe einen Kommentar