Sichere Datenübertragung zwischen cplace-Systemen mit GraphQL
GraphQL wurde ursprünglich von Facebook entwickelt, um die Entwicklung von APIs für Web Clients zu vereinfachen. Statt serverseitig für jeden Client und jeden Anwendungsfall eine spezifische Schnittstelle bereitzustellen, reicht mit GraphQL die Entwicklung einer einzigen generischen Query-Schnittstelle aus. Ausführliche Tutorials zu der Verwendung und Implementierung von GraphQL für Web APIs mit unterschiedlichen Programmiersprachen stehen auf graphql.org.
Anwendungsfall: Datenübertragung
Im Folgenden geht es um einen etwas ausgefalleneren Anwendungsfall, nämlich die Entwicklung einer generischen Komponente zur sicheren Datenübertragung zwischen cplace-Systemen.
cplace ist eine Anwendungsplattform mit Fokus auf Planungs- und Kollaborations-Anwendungen. Um derartige Anwendungen auf Basis von cplace zu bauen, kommt man für viele Anforderungen ohne Programmierung aus („No Code Development“): Power User können über spezielle Konfigurationsoberflächen eigene Datentypen, Attribute und Beziehungen samt den zugehörigen graphischen Widgets und Dashboards „zusammenklicken“, um ihre Fachdomäne abzubilden. Über die Einbindung von JavaScript unterstützt cplace zudem auch den sogenannten „Low Code“-Ansatz.
Wenn im cplace-Kontext bestimmte Daten von einem Quell-Server zu einem Ziel-Server übertragen werden müssen, soll natürlich auch der Mechanismus zur Auswahl und Übertragung der konfigurierten Daten ohne Programmierung auskommen, sondern generisch und konfigurationsgesteuert funktionieren – „No Code“ eben.
Aus diesem Grundprinzip und zusätzlichen Kundenwünschen ergaben sich die folgenden Anforderungen an die Entwicklung der Datentransfer-Komponente:
- Die vom Quell-Server bereitgestellte Schnittstelle muss jeweils dynamisch dem aktuell konfigurierten Datenschema folgen.
- Der Quell-Server muss kontrollieren können, welche Daten er an welche Ziel-Server weitergibt. Damit lässt sich ausschließen, dass vertrauliche Daten abfließen.
- Der Ziel-Server muss seinen Datenbedarf konfigurativ über eine Query definieren können.
- Zeitpunkte und Übertragungsumfänge sollen konfigurationsgesteuert definiert werden können. So könnten zum Beispiel „stabile“ Stammdaten jeweils nur am Wochenende synchronisiert werden, „schnell drehende“ Bewegungsdaten dagegen in kürzeren Abständen.
cplace bietet unter der Bezeichnung „Cross-Company eXchange (CCX)“ bereits eine Komponente zur Datenübertragung. Der Shared-Source-Ansatz der collaboration Factory ermöglicht es aber zusätzlich, ohne weiteres auch alternative Schnittstellentechnologien wie GraphQL zu integrieren. Diese Offenheit zeichnet cplace gegenüber proprietären Systemen aus und vereinfacht die Anbindung anderer Systeme - zum Rapid Application Development kommt die Rapid Application Integration.
GraphQL als Basistechnik
GraphQL funktioniert ähnlich wie SQL: Es bietet eine Sprache zur Definition von Datenschemas sowie zur Abfrage und Manipulation der entsprechenden Daten.
Die Abbildung zeigt ein Beispiel: Das Schema links in der Abbildung definiert unter anderem Projekte (Typ „Project“) mit zwei Attributen („name“ und „tagline“, jeweils vom Typ „String“) und einer Beziehung („contributors“ zu Entitäten des Typs „User“). Basierend auf diesem Schema kann nun die Query „gib mir die Tagline des Projekts mit Namen ‚GraphQL‘ zurück“ formuliert werden, deren Ergebnis ganz rechts zu sehen ist. Sowohl Query als auch Result liegen im JSON-Format vor.
Das jeweils aktuelle Schema können sich Clients über eine spezielle GraphQL-Abfrage besorgen. Es steht dann beispielsweise in JSON-Form zur Verfügung. Änderungen des Schemas sind grundsätzlich zur Laufzeit möglich. Wenn das geänderte Schema kompatibel zum bisherigen Schema ist (zum Beispiel, wenn lediglich neue Datenfelder hinzukommen), bleiben bereits bestehende Client-Queries weiterhin gültig.
Umsetzung
Die Umsetzung der Komponente zur Datenübertragung zwischen cplace-Systemen mit GraphQL ergibt sich mehr oder weniger direkt aus den Anforderungen:
Die Bereitstellung des aktuellen GraphQL-Schemas durch den Quell-Server erfordert den Zugriff auf das aktuell konfigurierte Server-Datenschema. Für alle Typen, Beziehungen und Attribute des cplace-Datenschemas müssen also passende GraphQL-Typen, Beziehungen und Attribute erzeugt werden, welche den Zugriff zur Laufzeit ermöglichen.
In unserem speziellen Anwendungsfall war das recht einfach möglich, da die Datenmodelle und Basisdatentypen von cplace gut zu den entsprechenden GraphQL-Konzepten passen.
Die verbleibenden Probleme ließen sich durch folgende Techniken lösen:
- Für einige spezielle cplace-Datentypen (z.B. DateTime und bestimmte Referenz-Typen) gab es im GraphQL-Standard keine Entsprechung. Deshalb wurden zusätzlich zu den bestehenden GraphQL-Basisdatentypen sogenannte „custom scalars“ erzeugt, wie bereits vom GraphQL-Standard vorgesehen.
- Die Benennung der Typen des Server-Datenschemas konnte nicht einfach in GraphQL übernommen werden, da GraphQL im Gegensatz zu cplace keine Punkte und Sonderzeichen in den Namen unterstützt. Deshalb wurden im generierten GraphQL-Schema Punkte durch Unterstriche ersetzt und Sonderzeichen (Unterstriche, Bindestriche, Umlaute etc.) durch in Unterstrichen eingebettete HTML-Codes (ohne das führende &) ersetzt. So wird z.B. aus „Abc.DEÄ“ im GraphQL-Schema und der entsprechenden Query „Abc_DE_auml_“.
Zur Kontrolle der abfließenden Daten durch den Quell-Server wurde eine Zugriffskontrolle über Zugriffs-Token und die Prüfung der abfragenden IP-Adresse implementiert. Daten und Strukturen, die nicht übertragen werden dürfen, lassen sich im erzeugten GraphQL-Schema via Konfiguration ausblenden.
Die Definition der Query auf dem Zielsystem erfolgt ebenfalls konfigurationsgesteuert. Wichtig für das Gelingen der Query samt nachfolgendem erfolgreichen Einlesen der abgerufenen Daten ist dabei, dass das Datenschema des Ziel-Servers mit dem entsprechenden Ausschnitt des Datenschemas des Quell-Servers zusammenpasst. Um dies zu testen, gibt es einen Schema-Validator, mit dem die Struktur und die Typen gegen die Datenbasis geprüft werden können. Da das Datenschema sich jederzeit dynamisch ändern kann, sind die Abfragen zusätzlich durch entsprechende Prüfungen und GraphQL-Fehlermeldungen abgesichert.
Schließlich wurde ein Konfigurationsmechanismus entwickelt, über den Übertragungs-Zeitpunkte und Umfänge (über die auszuführenden GraphQL-Queries) festgelegt werden können.
Erfahrungen
GraphQL lässt sich grundsätzlich schnell erlernen, bietet aber eine Tiefe, die erst überblickt und dann auch richtig angewendet werden muss. Bis auf wenige Ausnahmen (insbesondere die Unterstützung von Typen mit Punkten oder Sonderzeichen im Namen) haben uns bei der Umsetzung die von GraphQL standardmäßig angebotenen Konzepte, Mechanismen und Schnittstellen ausgereicht. Auch die verwendeten Java-Bibliotheken im GraphQL-Umfeld sind ausgereift.
Besonders hilfreich beim Testen und Debuggen war die grafische Abfrage-Oberfläche GraphiQL, mit deren Hilfe man interaktiv sowohl das generierte Datenschema als auch darauf basierende Beispielabfragen überprüfen kann.
Spezielle Maßnahmen, um die Performanz zu optimieren, waren für unseren Anwendungsfall nicht erforderlich: Bis hin zu einigen hunderttausend Datensätzen ließen sich die Daten im JSON-Format problemlos aus dem cplace-Quellsystem auslesen, übertragen und transaktionsgesteuert im cplace-Zielsystem persistieren.
Autoren: Sebastian Zimmer (Software Developer), Dr. Klaus Bergner (Geschäftsführer), Holger Spiering (Software Architect)