PostGraphile-Schema erweitern & verfeinern: Smart Tags

Wer sich schon einmal grundlegend mit PostGraphile beschäftigt hat (PostgreSQL, GraphQL & PostGraphile – ein Überblick), wird sich vielleicht fragen: „Das ist ja super, um einfache CRUD-Anwendungen zu bauen; aber das reicht nicht für unsere Bedürfnisse, die wir an ein API stellen!“ – oder etwas Ähnliches.

Allerdings bekommen wir von PostGraphile nicht einfach nur allerlei Queries, CRUD Mutations und Erkennung von Relationen für unser Datenbankschema geschenkt! Es gibt dazu noch eine Reihe an Möglichkeiten, die Funktionsweise von PostGraphile zu konfigurieren und genau auf unsere Bedürfnisse zuzuschneiden, um auch eigene Geschäftslogik und spezielle Use-Cases in unseres GraphQL-API zu unterstützen.

Wir wollen hier anhand von möglichst einfachen, jedoch praxisnahen Beispielen aufzeigen, wie wir PostGraphile verwenden und nicht nur trotz, sondern mit Hilfe der starken Automatisierung, auch komplexe Use-Cases abdecken können und weiterhin von der Performance, Typsicherheit, und den guten GraphQL-Standards (die uns PostGraphile direkt mitliefert) profitieren!

PostGraphile-Schema erweitern & verfeinern


Es wird umfangreich

Mit Hilfe von Smart Tags steuern wir genau, wie Spalten unserer Tabellen angepasst werden können, um genauer in unser Schema-Design zu passen. Anschließend erkunden wir Computed Columns, welche uns ganze SQL-Funktionen verwenden lässt, um unser Schema anzureichern. Zum Ende blicken wir noch auf das Plug-in-System von PostGraphile, das uns auch die träumerischsten Sonderwünsche erfüllen lässt.

Damit unsere Synapsen nicht mit zu viel Text auf einmal geflutet werden, sind die drei Themen auf einzelne Posts aufgeteilt. Aber keine Panik, Ihr braucht kein Abo abzuschließen: wir bringen alle drei Teile dieser Miniserie im Laufe dieser Woche heraus, damit das ganze zwar leicht verdaulich bleibt aber immer noch als eine zusammenpassende Mahlzeit verspeist werden kann.

Diese Miniserie sollte für jede Person, die schon einmal Grundlegend mit Datenbanken und SQL-Funktionen zu tun hatte, sehr leicht verständlich sein, wer jedoch noch einmal eine Auffrischung möchte, dem empfehle ich den ersten Teil der unserer PostGraphile-Serie.

Für die Miniserie haben wir unser Beispielprojekt auf GitHub mit einem extra Branch ausgestattet, damit das ganze auch in Code nachvollziehbar ist. Mit den einzelnen Commits sollte es für euch möglich sein, die hier aufgezeigten Schritte nachzuvollziehen und gegebenen Falles selbst ein bisschen damit zu spielen.

Doch genug der vielen Worte – lasst uns durchstarten!

Smart Tags

Eine der einfachsten Möglichkeiten unser GraphQL-Schema anzupassen, sind Smart Tags. Mit diesen können wir diverse Annotationen an unsere Tabellen, Spalten, SQL-Funktionen oder gar Relationen setzen.

Mit Hilfe von Smart Tags können wir bequem sowohl simple Anpassungen, wie bspw. eine Umbenennung von Feldern, weglassen von Feldern von bestimmten Tabellen, oder gar die Aktivierung von komplexen, zusätzlichen Plug-Ins steuern.

Wenn wir das Beispiel aus einem vorherigen Beitrag der Reihe – eine einfache Autoren- und Blog-Verwaltung – wieder aufgreifen und mit Hilfe von PostGraphile das Schema zu einem GraphQL-API erheben:

CREATE TABLE Writer (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    surname TEXT NOT NULL,
    nickname TEXT
);
CREATE TABLE Blogpost (
    id SERIAL PRIMARY KEY,
    title TEXT NOT NULL,
    content TEXT NOT NULL,
    blogpost_type BLOGPOST_ENUM NOT NULL,
    writer_id SERIAL REFERENCES Writer(id)
)

In der „echten“ Welt sollten Autoren sich authentifizieren können – in einem späteren Post in dieser Reihe gehen wir darauf ein, wie sogar die Authentifizierung mittels JWT-Tokens mit PostGraphile funktionieren kann. Was wir also zunächst benötigen, ist eine Passwort-Spalte an der Tabelle „Writer“:

-- schema.sql
CREATE TABLE Writer (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    surname TEXT NOT NULL,
    nickname TEXT,
    password TEXT NOT NULL -- Neue Spalte "password"
)
-- data.sql
CREATE EXTENSION IF NOT EXISTS pgcrypto; -- pgcrypto ist eine Erweiterung für Postgres, welche uns cryptographie - Funktionen direkt in SQL zur Verfügung stellt.
INSERT INTO Writer (name, surname, password) --
VALUES ('Emanuel', 'Vollmer', crypt('superSecret', gen_salt('bf', 8)))

Wenn wir anschließend einen Blick auf unser interaktives GraphiQL werfen, können wir sehen, dass der Passwort-Hash nun auch automatisch in unser GraphQL-Schema übernommen wurde:

Mit Hilfe von Smart Tags können wir dieses Verhalten nun beeinflussen.

Aufbau von Smart Tags

Smart Tags haben zuerst einen Namen und können drei unterschiedliche Datentypen halten: ein einfaches true , einen String oder ein Array von Strings. Die beiden einfachsten Varianten, Smart Tags zu vergeben sind

Darüber hinaus können Smart Tags auch programmatisch mit dem makePgSmartTagsPlugin oder einem komplett eigenen Plug-In in TypeScript erstellt und erweitert werden.

Im dritten Teil dieses Posts gehen wir übrigens noch einmal genauer auf das Plug-In-System von PostGraphile ein.

Built-in Smart Tags

PostGraphile bietet eine Reihe von vorgefertigten Smart Tags, die wir direkt verwenden können:

@deprecated

@deprecated erzeugt eine Deprecation-Warning im GraphQL-Schema für betroffene Entitäten. Zum Beispiel:

comment on column Writer.nickname is E'@deprecated Use name instead.';

@name

Mit Hilfe von @name können wir ganze Tabellen, Spalten, Typen oder sogar Funktionen für unser GraphQL-Schema umbenennen:

comment on column Writer.surname is E'@name lastname' 

Die Spalte surname ist im GraphQL schema nun als lastname zu finden.

@omit

Entfernt eine Entität, also einzelne Spalten, Tabellen, Relationen oder gar Funktionen vom Schema. Wir können granular steuern, ob beispielsweise ein Feld bei einer create-Mutation zwar benötigt wird, aber bspw. mit @omit update nicht in update-Mutations zur Verfügung steht.

@sortable

Wenn eine Computed Column ein Set an Werten (wie Tabellen und Views) zurück gibt, ermöglicht @sortable das orderBy-Argument im GraphQL-Schema für alle Spalten aus der von der Funktion zurück gegebenen Struktur.

Wenn @sortable an einer Computed Column angewandt wird die lediglich einfache Werte zurück gibt, wird ermöglicht, dass die Spalte als Argument für orderBy der Eltern-Tabelle verwendet werden kann.

@filterable

Analog zu @sortable wird bei Computed Columns die eine tabellenartige Struktur zurück geben, das condition -Argument für alle Spalten der aus der zurück gegeben Tabellenstruktur aktiviert.

Genauso wie bei @sortable verhält es sich auch, wenn Computed Columns skalare Werte zurück geben: somit kann nach diesen Werten in der Elterntabelle gefiltert werden.

Keine Sorge, Computed Columns sind keine Schwarze Magie. Wir gehen direkt nach diesem Teil des Artikels noch einmal genauer auf sie ein.

Alle Built-In Smart Tags finden wir in der PostGraphile-Dokumentation.

SmartComments

Mit Hilfe des Smart Tags @omit können wir also unseren Passwort-Hash aus dem API heraushalten. Dazu reicht ein einfacher Kommentar an der Spalte Writer.password:

comment on column Writer.password is E'@omit create,read,update,delete,all,many'; 

Bei all und many geht es hier übrigens nicht um die Menge der Writer, sondern um Queries, die sich auf die Relationen zu oder von Writer beziehen. Beispielsweise können wir bei Connections, die verschachtelt abgefragt werden können, spezielle Felder weg lassen, welche wir bei der direkten Query auf die Tabelle weiterhin ausliefern.

Und schon wird die Spalte password aus unserem Schema entfernt:

postgraphile.tags.json5

Alternativ und zusätzlich zu Kommentaren an unseren Datenbank-Entitäten können wir mit Hilfe der postgraphile.tags.json5 ebenso Smart Tags verwenden, um unsere Passwort-Spalte aus dem Schema zu halten:

{
  version: 1,
  config: {
    class: {
      writer: {
        description: "Ein Author auf unserem Blog",
        attribute: {
          password: {
            tags: {
              omit: "create,read,update,delete,all,many",
            },
          },
        },
      },
    },
  },
}

Unter dem Key class können wir nicht nur Tabellen, sondern auch Typen, Views, und Materialized Views angeben und konfigurieren.

Besonders komfortabel ist, dass PostGraphile die Einstellungen von beiden Seiten (also ob Kommentar oder Einstellung per postgraphile.tags.json5) automatisch zusammenführt. Sollten Entitäten bereits Einstellungen haben und in der postgraphile.tags.json5 erneut gesetzt werden, werden bestehende Einstellungen mit denen aus postgraphile.tags.json5 auf der selben Ebene überschrieben oder ergänzt.

Hat man also erst einmal angefangen über Kommentare Einstellungen vorzunehmen, schließen sich diese Einstellungen nicht gegenseitig aus. Wir müssen noch nicht einmal unseren Kommentar den wir per SQL gesetzt haben löschen, da die Einstellung per postgraphile.tags.json5 als letzte gilt.

Besonders in frühen Phasen eines Projektes, während man noch mit dem groben Design des API beschäftigt ist, können wir also frei experimentieren und müssen nicht ständig Einstellungen zurückrollen und neu einspielen.

Die komplette Übersicht zu SmartTags ist auf der Dokumentationsseite von PostGraphile zu finden.

Ausblick

Das war es dann auch schon mit der ersten Portion Smart Tags. Einen Blick auf die großartige Dokumentation zu Smart Tags zu werfen lohnt sich! Vielleicht finden wir direkt noch ein paar weitere, die für uns spannend sein können.

Wir machen als nächstes direkt weiter mit Computed Columns. Da wollen wir dann nicht nur Dinge aus unserem Schema raus halten, sondern Informationen gezielt anreichern. Es gibt noch einmal ein bisschen mehr SQL und eine ganze Menge Spaß!

Dran bleiben lohnt sich also; wir gehen noch einen Schritt weiter in die Materie und toben uns ein wenig mit PostGraphile aus. Und wenn ihr alle Artikel im Überblick haben möchtet, dann habe ich hier noch eine Übersicht für euch:

PostGraphile in-depth



Für neue Blogupdates anmelden:


Schreibe einen Kommentar

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