- Hauptteil
- Zugangskonzept
- Allgemeines
- Rechtekonzept: operative, administrative und globale Rechte
- Gruppen und Konten für Bereichsbetreuer
- Administration der Gruppen und OE-Betreuer durch OE-Betreuer
- Administration der Dienstkonten durch OE-Betreuer
- Verwendung der Dienstkonten durch KIT-Benutzerkonten
- Administration der Dienst-Unterkonten und Dienst-Untergruppen durch KIT-Benutzerkonten
- Authentifizierung
- URI-Schema
- Requests
- Authentifizierung
- Unterstützte Methoden
- POST-Request
- Requests als Einzelbefehls-Aufruf
- Requests als Mehrfachbefehls-Aufruf
- Ausgabe von Objekten relational verbundener Objekttypen mit JOIN-Anweisungen
- Bedingte Ausführung eines Statements mit der WHEN-Anweisung
- Wiederholte Ausführung eines Statements mit der RefParams-Anweisung
- Steuerung der Constraint-Validierung
- Generischer Objekttyp
- GET-Request
- POST-Request
- Antwort-Datenstruktur bei fehlerfreier Transaktion
- Antwort-Datenstruktur im Fehlerfall (Exception, Transaktionsabbruch)
- Indexabfragen
- Abfragen der Systemdaten
- Versionsangaben
- Zugangskonzept
Hauptteil
Zugangskonzept
Allgemeines
Die Zugriffe auf die WebAPI erfolgen auf Basis eines Benutzerkontos (NetDB-Konto) und eines zugeordneten Access Tokens. Um das Risiko der Kompromittierung eines Kontos zu minimieren und mögliche Einsatzprofile besser strukturieren zu können, gibt es in der NetDB 2 Arten von Benutzerkonten:
- Hauptkonten, mit den beiden Varianten
- KIT-Benutzerkonten, primär im KIT-IDM verwaltet. Dh. das Benutzerkonto muss im IDM existieren, bevor es in der NetDB angelegt werden kann.
- NetDB-Dienstkonten, ausschließlich in NetDB verwaltet (nicht im IDM vorhanden).
- Unterkonten für beide Varianten der Hauptkonten, ausschließlich in NetDB verwaltet (nicht im IDM vorhanden).
Über ein Konto werden die Zugriffsrechte der ihm zugeordneten Access Token abgebildet. Die Tokenvergabe ist wie folgt geregelt:
-
KIT-Benutzerkonten sind zur direkten Nutzung des Web-Portals (NETVS) vorgesehen und verwenden temporäre (Session-)Token. Diese Token werden automatisch bei Anmelden im NETVS bereitgestellt.
-
NetDB-Dienstkonten sind zur indirekten Nutzung des Web-Portals (NETVS) vorgesehen. Indirekt bedeutet, dass sie via Sudo-Feature als ausführendes Konto einer Transaktion eingesetzt werden (s. Verwendung durch zugeordnete KIT-Benutzerkonten). Sie verwenden daher kein NETVS-Session-Token, können aber ebenso Unterkonten haben, die den direkten WebAPI-Zugang über statische Token nutzen. Die Administration erfolgt ausschließlich durch OE-Betreuer.
-
Unterkonten sind ausschließlich für den direkten WebAPI-Zugang vorgesehen und verwenden statische Token. Deren Token müssen vom Inhaber des Hauptkontos über NETVS eingerichtet werden. Ist das Hauptkonto ein Dienstkonto, erfolgt die Einrichtung durch die KIT-Benutzerkonten der Gruppe des Dienstkontos.
Unterkonten können vom Inhaber eines Hauptkontos jederzeit nach eigenem Ermessen angelegt, modifiziert oder gelöscht werden. Jedem Unterkonto (und den zugehörigen Access Token) ist dadurch genau ein Hauptkonto zu- und übergeordnet. Ebenso kann der Inhaber des Hauptkontos im Rahmen seiner eigenen Rechte auch die Rechte seiner Unterkonten (Rollen und Untergruppen mit Namensräumen bzw. Adressräumen) verwalten. Zusätzlich kann ein Konto als ‘Nur-Lese-Konto’ eingestellt werden. Dadurch ist der Zugriff auf datenmodifizierende WebAPI-Funktionen gesperrt. Diese Sperre ist rein funktional und hat daher Vorrang vor allen anderen Rechten und wirkt davon unabhängig.
Auch diese Einstellung kann der Inhaber des Hauptkontos jederzeit für alle seine Unterkonten ändern. Sie kann für KIT-Hauptkonten nur durch ein anderes Konto mit erweiterten Rechten zurückgenommen werden.
Unterkonten haben eine funktionale Sperre für
- die Anmeldung im NETVS (da sie kein Passwort haben)
- sicherheitsrelevante Funktionen (Modifizierungen an Konten einschl. Rechte- bzw. Rollenzuordnungen)
Diese Sperre wirkt ebenfalls unabhängig davon, ob das Unterkonto tatsächlich die benötigten Rechte hat. Die gesperrten Funktionen können daher nur mittels Hauptkonto ausgeführt werden. Unterkonten dürfen nur ihre eigenen Access-Token modifizieren.
Rechtekonzept: operative, administrative und globale Rechte
- Operative Rechte erlauben den Zugriff auf die eigentlichen Nutzdaten innerhalb der entsprechenden Datenbereiche (z.B. FQDNs in Namensräumen, Adressen in Adressräumen). Um operative Rechte ausüben zu können, sind entweder globale Rechte oder Gruppenmitgliedschaften erforderlich.
- Administrative Rechte erlauben den Zugriff auf die Administrationsdaten (Gruppen und deren Inhalte, OE-Betreuer), über die z.B. Namensräume oder Adressräume der Gruppen definiert werden, oder weitere OE-Betreuer eingetragen oder bestehende entfernt werden. Um administrative Rechte ausüben zu können, sind entweder globale Rechte oder die Zuordnung des Benutzerkontos zu einer Organisationseinheit (OE-Betreuer) erforderlich.
- Globale Rechte erlauben den objekttyp-basierten Zugriff (Objekte eines Typs), oder den systemweiten Zugriff. Globale Rechte werden per Rollenzuordnung definiert. Sie haben generell Vorrang vor den beiden ersten und werden daher in den folgenden Erläuterungen nicht jedesmal extra erwähnt.
Gruppen und Konten für Bereichsbetreuer
Gruppen dienen der effizienten Zuordnung der Netzbereiche (Adressräume, Namensräume) zu Benutzerkonten. Einer Gruppe sind BCDs, Domains und Benutzerkonten zugeordnet. Die zugeordneten Benutzerkonten werden auch als Gruppenmitglieder bezeichnet. Den Gruppenmitgliedern sind somit Domains und BCDs zugeordnet, woraus sich die operativen Zugriffsrechte der Gruppenmitglieder ableiten lassen. Analog zu den beiden Kontenarten gibt es auch 2 Arten der Gruppen:
- Hauptgruppen (können nur Hauptkonten enthalten; können als KIT-Benutzergruppen primär im IDM oder primär in NetDB verwaltet werden)
- Untergruppen (enthalten jeweils genau ein Hauptkonto des Eigentümers und können darüberhinaus nur dessen eigene Unterkonten enthalten; nur primär in NetDB verwaltet; nicht im IDM vorhanden)
Domain- und BCD- Zuordnungen in Untergruppen können nur im Rahmen vorhandener Zuordnungen ihrer Hauptgruppe bestehen.
- Der Namensraum aller Gruppenmitglieder wird durch die Domains ihrer Gruppen definiert.
- Der Adressraum aller Gruppenmitglieder wird durch die Subnetze der BCDs ihrer Gruppen definiert.
Hauptgruppen in der NetDB können in 2 Modi benutzt werden:
- IDM-synchron: alle Gruppenmitglieder werden primär über die IDM-Gruppenverwaltung zugeordnet. Beim Synchronisationsvorgang wird der Stand der Gruppenmitglieder der IDM-Gruppe auf die NetDB-Gruppe übertragen. Wird der Name und/oder die Beschreibung der IDM-Gruppe (idm-seitig) geändert, wird diese Namensänderung beim nächsten Synchronisationsvorgang auch auf die NetDB-Gruppe übertragen.
- nicht-IDM-synchron: alle Gruppenmitglieder werden primär in der NetDB verwaltet.
Wird ein KIT-Benutzerkonto einer Hauptgruppe im IDM zugeordnet, und möchte der Kontoinhaber eine eigene Untergruppe mit eigenen Unterkonten erstellen, kann er dies erst, nachdem die Hauptgruppe synchronisiert wurde (und die Gruppenmitglieder aktualisiert sind). Umgekehrt werden Untergruppen und deren Unterkonten automatisch aus einer Hauptgruppe entfernt, wenn auch ihr Hauptkonto aus der Hauptgruppe entfernt wurde (unabhängig davon, ob die Hauptgruppe IDM-synchron ist oder nicht). Die automatische Synchronisation erfolgt dabei nicht in Echtzeit, sondern stündlich für alle Gruppen. Sie kann aber auch jederzeit explizit für eine bestimmte Gruppe angefordert werden, um eine sofortige Synchronisation zu erreichen. Der Synchronisationsvorgang ist IDM-seitig nur-lesend; alle Schreibzugriffe erfolgen ausschließlich NetDB-seitig.
Administration der Gruppen und OE-Betreuer durch OE-Betreuer
Für die Gruppenadministration ist die Zuordnung eines Benutzerkontos zu einer Organisationseinheit (OE) erforderlich. Diese Zuordnung wird nicht vom IDM übernommen, sondern primär in der NetDB abgebildet. Der Inhaber des zugeordneten Kontos wird dadurch OE-Betreuer dieses OE-Teilbaums (dh. der zugeordneten OE einschließlich aller darunterliegenden OE) und bekommt das Administrationsrecht für
- alle Hauptgruppen, die (mittels Gruppen-OE) einer OE seines OE-Teilbaums zugeordnet sind
- weitere, neu einzutragende OE-Betreuer innerhalb seines OE-Teilbaums
- zu löschende OE-Betreuer innerhalb seines OE-Teilbaums
- alle Dienstkonten, die einer OE seines OE-Teilbaums zugeordnet sind. Dienstkonten haben dadurch keine OE-Administrationsrechte.
Ebenso bekommt er das Administrationsrecht für alle Domains und BCDs, deren OEs seinem OE-Teilbaum zugeordnet sind. Zusammengefasst:
- Alle Netzbereiche (BCDs), die seinem OE-Teilbaum zugeordnet sind, bilden den administrativen Adressraum des OE-Betreuers.
- Alle Domains, die seinem OE-Teilbaum zugeordnet sind, bilden den administrativen Namensraum des OE-Betreuers.
- Die Mitgliedschaft des OE-Betreuerkontos in den Hauptgruppen des OE-Teilbaums ist zwar davon unabhängig, aber Voraussetzung, um das Operationsrecht auf Namensraum und Adressraum auszuüben.
Das Administrationsrecht für Hauptgruppen, deren OE im eigenen OE-Teilbaum liegt, umfasst außerdem:
- Eintragen neuer Gruppen
- Ändern der Gruppenattribute (Name, OE, Beschreibung, IDM-Synchronisation)
- Eintragen oder Löschen der Mitglieder
- Eintragen der Domains (oder deren Subdomains), soweit sie dem eigenen OE-Teilbaum zugeordnet sind und
- bei rekursiver Wirkung die Domain-OE gleich oder oberhalb der Gruppen-OE liegt
- bei nicht-rekursiver Wirkung die Domain-OE gleich der Gruppen-OE ist
- Eintragen der BCDs, soweit sie dem eigenen OE-Teilbaum zugeordnet sind und
- bei rekursiver Wirkung die BCD-OE gleich oder oberhalb der Gruppen-OE liegt
- bei nicht-rekursiver Wirkung die BCD-OE gleich der Gruppen-OE ist
- Löschen der BCDs, Domains
Untergruppen werden ausschließlich durch ihre Eigentümer administriert.
Administration der Dienstkonten durch OE-Betreuer
Die besondere Eigenschaft in der Administration der Dienstkonten besteht darin, dass diese nicht an ein einzelnes KIT-Benutzerkonto gebunden ist, sondern immer durch alle derzeitigen OE-Betreuer vorgenommen werden kann.
Scheidet ein OE-Betreuer als Person aus oder kommt eine neue Person als OE-Betreuer hinzu, überträgt sich die Administrationsfähigkeit automatisch (durch die gleiche OE-Zuordnung). Das Administrationsrecht der OE-Betreuer für Dienstkonten umfasst:
- Eintragen neuer Dienstkonten und diesen mindestens eine ihrer eigenen OEs zuordnen (transaktional gleichzeitig)
- Ändern der Kontenattribute (Dienst-Kennung, Beschreibung, Nur-Lesezugriff)
- Ändern der OE-Zuordnung (neue OE zuordnen; bestehende OE-Zuordnung löschen)
- Ändern der Hauptgruppen-Zuordnung (Eintragen in bzw. Löschen aus Hauptgruppen, deren OE im eigenen OE-Teilbaum liegt)
- Löschen des Dienstkontos,
wenn alle OEs des Dienstkontos auch in allen OE-Teilbäumen des OE-Betreuerkontos liegen. Diese Bedingung wird bei Neueintrag durch die transaktional gleichzeitige OE-Zuordnung erfüllt. Dienstkonten haben keine OE-Administrationsrechte, wie es bei Hauptkonten der Fall ist.
Gruppen, die IDM-synchron gehalten werden, können kein Dienstkonto enthalten, da NetDB-Dienstkonten IDM-seitig nicht bekannt sind und daher bei der Synchronisation gelöscht werden würden.
Verwendung der Dienstkonten durch KIT-Benutzerkonten
Die besondere Eigenschaft in der Nutzung der Dienstkonten besteht darin, dass diese nicht auf ein einzelnes KIT-Benutzerkonto beschränkt ist, sondern für mehrere KIT-Benutzerkonten durch eine Gruppenmitgliedschaft festgelegt werden kann.
Dienstkonten einschließlich deren Dienst-Unterkonten können durch KIT-Benutzerkonten, die sich in derselben Hauptgruppe wie das Dienstkonto befinden,
als ausführendes Konto einer Transaktion (Schreib-Lese-Zugriff) eingesetzt werden
(via Sudo-Feature, s. Transaktionsparameter su_login_name
im Zielabschnitt).
OE-Betreuer müssen sich selbst dieser Gruppe zuordnen, um dieses Recht auszuüben; dh. die OE-Zuordnung allein reicht dafür nicht aus. Damit sind KIT-Hauptkonten einer Gruppe berechtigt, Transaktionen mit den Rechten eines dieser Gruppe zugeordneten Dienstkontos -einschließlich dessen Dienst-Unterkonten- auszuführen. Diese benötigte Gruppenzuordnung obliegt der Administration durch OE-Betreuer.
Administration der Dienst-Unterkonten und Dienst-Untergruppen durch KIT-Benutzerkonten
Dienst-Unterkonten und Dienst-Untergruppen werden (in analoger Weise zu eigenen Unterkonten/Untergruppen) administriert, indem das Dienst-Hauptkonto als eingesetztes Konto durch KIT-Benutzerkonten (wie oben beschrieben) verwendet wird.
Authentifizierung
WebAPI-Zugriffe (Requests) werden über ein token-basiertes Verfahren (OAuth 2.0 Bearer Token) authentifiziert. Dazu kann jedem Unterkonto ein oder mehrere sog. Access Token zugeordnet werden. Über diese Zuordnung erfolgt die Identifikation. Der WebAPI-Zugriff erfolgt also mit den Rechten des Kontos, das dem verwendeten Access Token zugeordnet ist. Das Token bzw. dessen Authentifizierungstext wird vom System (NetDB) automatisch generiert und ist sicherheitstechnisch wie ein geheimer Schlüssel bzw. Klartext-Passwort zu betrachten. Bitte beachten Sie auch die Sicherheitshinweise dazu.
Die Registrierung eines Tokens muss je nach Umgebung über die NETVS-Webseite
- Produktionsumgebung: https://netvs.scc.kit.edu
- Testumgebung: https://netvs-test.scc.kit.edu
- Entwicklungsumgebung: https://netvs-devel.scc.kit.edu
vorgenommen werden.
Ein Access Token umfasst folgende Hauptdaten:
- Benutzerkennung des Kontos
- Ablaufdatum (kann auch leer sein, falls Token unbegrenzt gültig sein soll). Token, deren Ablaufdatum überschritten sind, sind für den WebAPI-Zugriff gesperrt. Sie bleiben aber bestehen, bis das Löschdatum erreicht ist.
- Löschdatum: Datum der endgültigen Löschung des Tokens. Wird bei jedem Zugriff automatisch verlängert (je nach Typ, s. dort)
- zuletzt angemeldet: Datum des letzten Zugriffs, der mit diesem Token erfolgte
- zuletzt generiert: Datum, wann der aktuell gültige Authentifizierungstext erzeugt wurde
- Beschreibungstext: benutzerseitige Information, frei wählbar
- Authentifizierungstext: das eigentliche Identifizierungsmerkmal des Benutzerkontos (systemgeneriert). Wird nur einmalig nach Erzeugen oder Ändern angezeigt, danach nicht mehr abfragbar.
- Typ, Art des Tokens:
- statisch, Inaktivitätsintervall 200 Tage, nur für Unterkonten
- temporär mit kurzem Inaktivitätsintervall (1 Stunde), nur für Hauptkonten
- temporär mit langem Inaktivitätsintervall (1 Monat), nur für Hauptkonten
- gpk: Globaler Primärschlüssel
Statische Token werden für den WebAPI-Zugriff der Unterkonten verwendet. Der Inhaber des Hauptkontos kann für statische Token seiner Unterkonten jederzeit einen neuen Authentifizierungstext vom System generieren lassen, ebenso kann er das Ablaufdatum und den Beschreibungstext jederzeit neu bestimmen oder das Token löschen. Wichtig: Löschbare Token werden täglich automatisch gelöscht. Das Löschdatum ist erreicht, wenn
- das Ablaufdatum um 200 Tage überschritten ist
- kein Ablaufdatum definiert ist und die letzte Benutzung (Login) älter als 200 Tage ist
- das Token unbenutzt, kein Ablaufdatum definiert und das Erzeugungsdatum älter als 200 Tage ist
Eine Löschung (bspsw. selten genutzter Token) kann verhindert werden, indem rechtzeitig eine Re-Validierung durch z.B. einen Request mit leerer Transaktion ausgeführt wird.
Temporäre Token werden typischerweise für Web-Browser-Sessions der Hauptkonten verwendet. Sie werden nach Überschreiten des Ablaufdatums, maximal aber nach 1 Monat automatisch gelöscht. Bei Token mit kurzem Inaktivitätsintervall wird das Ablaufdatum mit jedem Zugriff um das festgelegte Intervall (1 Stunde) verlängert. Der Inhaber des Hauptkontos kann eigene temporäre Token jederzeit löschen; Änderungen an temporären Token sind gesperrt.
Hinweise zur Registrierung von Unterkonten
Wir empfehlen Ihnen aus Sicherheitsgründen (Schadensminimierung im Mißbrauchsfall):
- für den WebAPI-Zugang nicht Ihr persönliches, ggf. sogar höher privilegiertes Benutzerkonto zu verwenden, sondern je nach Einsatzprofil ein oder mehrere Unterkonten mit den mindestnötigen Privilegien anzulegen und einzusetzen.
- die Trennung der Einsatzprofile nach Nur-Lese-Zugriffen und Schreib-Lese-Zugriffen, um im ersten Fall Nur-Lese-Konten einzusetzen.
Sicherheitshinweise zur Token-Benutzung
Der Authentifizierungstext ist das Identifizierungsmerkmal des eindeutig zugeordneten Benutzerkontos und ist deshalb wie ein privater bzw. geheimer Schlüssel (Klartext-Passwort) zu betrachten. Der Besitzer des Authentifizierungstextes kann WebAPI-Requests mit den Rechten des zugeordneten Kontos ausführen. Um einen Mißbrauch bzw. Kompromittierung zu vermeiden, beachten Sie bitte folgendes:
- den Authentifizierungstext nur in einer Umgebung speichern, in der der Zugriff unberechtigter Dritter nach aktuellen Sicherheitsstandards ausgeschlossen ist.
- für zeitlich begrenzte Einsatzprofile das Ablaufdatum im Voraus entsprechend einstellen (ein z.B. ‘vergessenes’ Token ist dadurch automatisch deaktiviert). Nach Überschreiten des Ablaufdatums kann das Token zwar nicht mehr benutzt werden, bleibt aber für weitere 200 Tage in der NetDB gespeichert. In dieser Zeit kann es durch Ändern der Ablaufdatums wieder freigeschaltet werden, ohne dass der Authentifizierungstext verändert werden muss.
URI-Schema
Alle Zugriffe (Requests) werden über URIs adressiert, deren Aufbau nach folgendem Schema erklärt wird:
- Werte in spitzen Klammern sind Platzhalter
- Werte in eckigen Klammern sind optional
- großgeschriebene Platzhalter sind konstant; kleingeschriebene sind variabel
- Beschreibungstext wird von Anführungszeichen
""
umgeben
<BASE-URI>/<vmajor>.<vminor>/<sys>/<objtype>/<function>[<params>]
<BASE-URI>: https://api.netdb.scc.kit.edu "Produktionsumgebung"
https://api.netdb-test.scc.kit.edu "Testumgebung (täglich veraltete Kopie der Produktionsumgebung)"
https://api.netdb-devel.scc.kit.edu "Entwicklungsumgebung (unbestimmt veraltete Kopie der Produktionsumgebung mit Modifikationen)"
<vmajor> : "natürliche Zahl, Hauptnummer der Version (Versionsreihe, Major Release)"
<vminor> : "natürliche Zahl, Unternummer der Version innerhalb der Versionsreihe (Minor Release)"
<sys> : "WebAPI-Systemname, Teilbereich von Anwendungsdaten (z.B. dns, nd)"
<objtype> : "WebAPI-Objekttyp-Bezeichnung (z.B. record, module, fqdn)"
<function>: "WebAPI-Funktion: Zugriffsart (z.B. create, update, delete, list)"
<params> : "Parameterzeichenkette (query string) der Form ?<param1>=<value1>[&<param2>=<value2>[&...]]"
Alle rechtsseitig bzw. unterhalb von <BASE-URI>
stehenden Platzhalter im URI-Schema sind demnach variabel.
Ihre Wertebelegungen sind bei Versionswechseln als potentiell veränderbar zu betrachten
und können daher versionsweise unterschiedlich sein.
Eine Ausgabe der Wertebelegungen der variablen Platzhalter kann über
Indexabfragen oder über die Ausgabe (list-Funktion) der Objekttypen
/wapi/system
, /wapi/object_type
, /wapi/function
erreicht werden.
Der jeweilige URI zur Dokumentation kann durch Abfrage des <BASE-URI>
erreicht werden; er ist dort unter dem Bezeichner "doc_uri"
hinterlegt.
Die Inhalte der drei angegebenen Datenbanken (Produktions-, Test- und Entwicklungsumgebung) sind für sich unabhängig voneinander, aber:
- die Testdatenbank wird täglich nachts von der Produktionsdatenbank kopiert. Dort gemachte Änderungen sind also maximal für einen Tag sichtbar, weil sie anschließend wieder vom Stand der Produktionsdatenbank überschrieben werden.
- Die Entwicklungsdatenbank wird in unregelmäßigen Abständen von der Produktionsdatenbank kopiert; zusätzlich sind dort Modifikationen im Rahmen der Weiterentwicklung möglich. Selbstverständlich gibt es hierbei keinerlei Garantien oder Support.
Deren Datenbestände sind also “Momentaufnahmen” der Produktionsdatenbank und grundsätzlich als veraltet anzusehen. Demnach müssen auch ggf. neue Konto- bzw. Token-Registrierungen, die sofort auch in Test- und Entwicklungsumgebung benötigt werden, dort separat vorgenommen werden.
Requests
Ein Request entspricht einer Datenbank-Transaktion (TA).
Der Status einer TA kann aus der Antwort über den HTTP-Header netdb-transaction-state
abgefragt werden.
Definierte Stati:
not_executed
: die Transaktion wurde nicht ausgeführt (aufgrund eines vorausgehenden Fehlers, z.b. Authentifizierung)committed
: die Transaktion wurde fehlerfrei ausgeführtrolled_back
: die Transaktion wurde fehlerfrei ausgeführt, aber zurückgerollt (implizites oder explizites Transaktionsrollback)failed
: die Transaktion wurde zwar ausgeführt, aber durch eine Exception abgebrochen und zurückgerollt
Der Datenzugriffsmodus der TA kann aus der Antwort über den HTTP-Header netdb-transaction-access-mode
abgefragt werden.
Definierte Modi:
not_available
: nicht definiert (z.b. bei Exceptions oder leeren Transaktionen)read_only
: Nur-Lesezugriff, dh. die TA enthält keine datenmodifizierenden Funktionenwrite_only
: Nur-Schreibzugriff, dh. die TA enthält nur datenmodifizierende Funktionen, die keine Antwortdaten zurückgebenread_write
: Lese- und Schreibzugriff
Authentifizierung
Die Requests unterliegen grundsätzlich dem Zwang zur Authentifizierung. Davon ausgenommen sind Zugriffe, die ausschließlich auf den Systemdatenbereich erfolgen. Die Authentifizierung an sich ist nicht Bestandteil der eigentlichen Transaktion und wird vorher ausgeführt. Bei erfolgreicher Authentifizierung wird Zugriffsdatum und Zugriffszeit des Access Token aktualisiert, unabhängig davon, welches Ergebnis durch die Transaktion entsteht.
Authentifizierte Requests
Im HTTP-Header authorization
muss ein gültiges OAuth 2.0 Bearer Token übergeben werden.
Muster des HTTP-Headers:
authorization: Bearer ***AUTH-TOKEN-TEXT***
Bearer
bezeichnet das Authentifizierungsschema;
***AUTH-TOKEN-TEXT***
ist der Authentifizierungstext des Access-Tokens.
Zwischen beiden Angaben steht mindestens 1 Leerzeichen.
Jedes Access-Token ist genau einem Benutzerkonto zugeordnet, dessen Rechte bei der Ausführung des Requests gelten.
Nicht-authentifizierte Requests
Der HTTP-Header authorization
wird nicht angegeben oder ist leer.
Unterstützte Methoden
Als HTTP-Request-Methoden können POST
(generell) und GET
(nur für nicht-datenmodifizierende Funktionen)
verwendet werden. Als Zeichenkodierung wird ausschließlich UTF-8 verwendet. Zur Ablehnung des Requests führen:
- Authentifizierungsfehler
- nicht als UTF-8 dekodierbare Werte
- Übergabe von Parametern, die die jeweilige Funktion nicht erwartet
- Parameterwerte, deren JSON-Datenyp nicht mit dem JSON-Datentyp des Parameters übereinstimmt
- Parameterwerte, die sich nicht in den zugehörigen Datentyp konvertieren lassen
POST-Request
Diese Methode bietet die volle Funktionalität und ist für alle Funktionsaufrufe verwendbar.
Der Request Body muss ein gültiges JSON-Dokument sein, dem JSON-Schema im Versionsindex
unter dem Schlüssel transaction_json_schema
entsprechen und auch als solches deklariert sein (HTTP-Header: content-type:application/json
).
Ein ungültiges JSON-Dokument führt zur Ablehnung des Requests.
Requests als Einzelbefehls-Aufruf
Bei dieser Variante wird pro Request genau ein Objekt eines Objekttyps eines Systems mit einer Funktion behandelt. Sollen mehrere Objekte desselben Objekttyps und Systems mit derselben Funktion nach dieser Variante behandelt werden, ist pro Objekt ein separater Request (separate Transaktionen) erforderlich; es sei denn, die Funktion gestattet die Behandlung mehrerer Objekte gleichzeitig (Bulk-Funktion). URI-Schema unterhalb der Version:
/<sys>/<objtype>/<function>
Datenstruktur des Request Body:
Da System, Objekttyp und Funktion bereits im URI adressiert sind,
besteht das JSON-Dokument nur aus einem JSON-Dict mit den Schlüsseln old
, new
mit JSON-Dicts für die jeweiligen Parameter-Wertebelegungen.
old
beinhaltet die jeweiligen Parameterwerte vor der Änderung; new
diejenigen nach der Änderung:
{
"old": {
"<param_name>": <param_value>, ...
},
"new": {
"<param_name>": <param_value>, ...
}
}
Requests als Mehrfachbefehls-Aufruf
Pro Request können hier mehrere Befehle (Statements) mit jeweils unterschiedlichen Systemen, Objekttypen und Funktionen behandelt werden. URI-Schema unterhalb der Version:
/wapi/transaction/execute
Im Gegensatz zum Einzelbefehls-Aufruf sind System, Objekttyp und Funktion hier nicht im URI festgelegt, sondern werden im Request Body pro Statement angegeben. Bei diesem generischen Transaktionsaufruf können zusätzliche Steuerparameter in der Parameterzeichenkette übergeben werden:
-
dry_mode
(Boolean-Typ), Wertebelegung:true
gibt an, dass dieser Request (=Transaktion) nur als ‘Trockenlauf’ behandelt wird, d.h. alle Änderungen, die innerhalb des Requests stattfinden, werden zwar durchlaufen, aber an dessen Ende wieder verworfen (es erfolgt ein Datenbank-Transaktions-Rollback). Dieser Modus ist geeignet, um die Transaktion auf Fehler zu testen und daher nur sinnvoll, wenn datenmodifizierende Funktionen enthalten sind.false
(Standardwert) bewirkt die vollständige Abarbeitung des Requests, d.h. bei Fehlerfreiheit werden alle Änderungen gespeichert und sind für nachfolgende Requests sichtbar (es erfolgt ein Datenbank-Transaktions-Commit).- s.a. Abfrage des Transaktionsstatus
-
dict_mode
(Boolean-Typ, s.a. Antwort-Datenstruktur), Wertebelegung:true
gibt an, dass die äußere Ebene des Antwort-JSON-Dokuments (Transaktionsebene) ein JSON-Dict ist. Dessen Schlüssel sind gleichlautend zum zugehörigen Statement-Indexidx
des Request Body.false
(Standardwert) gibt an, dass die äußere Ebene des Antwort-JSON-Dokuments (Transaktionsebene) ein JSON-Array ist. Dessen Positionen sind gleichlautend zur zugehörigen Statement-Position des Request Body.
-
su_login_name
(Text-Typ)- Gibt den Login-Namen des einzusetzenden Benutzerkontos an, unter dessen Rechten die Transaktion ausgeführt werden soll.
- Der Parameter darf bei nicht-eigenen Konten nur mit Administratorrechten eingesetzt werden,
d.h. das authentifizierte Benutzerkonto ist Inhaber der Rolle
wapi.sudoer
. In diesem Fall wird die Transaktion zwingend zurückgerollt (unabhängig davon, welchen Wertdry_mode
hat). Man kann damit feststellen, ob die Transaktion fehlerfrei gelaufen wäre bzw. welche Daten das eingesetzte Konto sehen würde. - Bei eigenen Dienst-Hauptkonten oder eigenen Unterkonten sind keine Administratorrechte erforderlich und die Transaktion wird nicht zwingend zurückgerollt.
- s.a. Abfrage des Transaktionsstatus
Datenstruktur des Request Body:
Die gültige Struktur ist primär im JSON-Schema des Versionsindex unter dem Schlüssel transaction_json_schema
hinterlegt.
Da mehrere Statements möglich sind, besteht das JSON-Dokument aus einem äußeren JSON-Array, das die Transaktionsebene darstellt.
Dieses enthält wiederum JSON-Dicts, welche jeweils ein Statement darstellen.
[
{
"title": "",
"description": "",
"idx": "<sidx>",
"name": "<system_name>.<object_type_name>.<function_name>",
"old": { "<param_name>": <param_value>, ... },
"new": { "<param_name>": <param_value>, ... },
"old_ref_params": [ <old_ref_params_dict>, ... ],
"new_ref_params": [ <new_ref_params_dict>, ... ],
"old_ref_idx": "<old_ref_sidx>",
"new_ref_idx": "<new_ref_sidx>",
"ref_params_join_on_val_attrs_tuple": ["<param_name", ...],
"constraints_deferred": [ "<api_constraint_name>", ... ],
"constraints_immediate": [ "<api_constraint_name>", ... ],
"inner_join_ref": { "<ref_sidx>": "<referencing_constraint_name>" | "default" | "self" | null, ... },
"union_join_ref": { "<ref_sidx>": "<referencing_constraint_name>" | "default" | "self" | null, ... },
"anti_join_ref": { "<ref_sidx>": "<referencing_constraint_name>" | "default" | "self", ... },
"semi_join_noref": { "and": ["<fk_constraint_name>", ...], "or": ["<fk_constraint_name>", ...] },
"anti_join_noref": { "and": ["<fk_constraint_name>", ...], "or": ["<fk_constraint_name>", ...] },
"when": { "<when_condition_function>": [ <when_condition_function_arg>, ... ] }
}
]
Nachfolgend werden die Schlüssel der äußersten Ebene erklärt.
title
: dient nur der Dokumentation bzw. Lesbarkeit des Statementsdescription
: dient nur der Dokumentation bzw. Lesbarkeit des Statementsidx
: Statement-Index, der eine eindeutige Bezeichnung des Statements innerhalb der Transaktion ermöglicht. Der Statement-Index kann abweichend von der Statement-Position willkürlich vorgegeben/benannt werden; d.h. er ist unabhängig von der Position. Er wird als Zielreferenz für JOIN-Anweisungen, WHEN-Anweisungen und RefParams-Anweisungen sowie als Statement-Index im Antwort-JSON-Dokument (nur mitdict_mode
=true
, s. Antwort-Datenstruktur) verwendet. Wird die Position eines Statements, das eine Zielreferenz darstellt, verschoben (z.B. durch veränderte Anwendungslogik), müssen die Ziele der JOIN/WHEN-Anweisungen bzw. Bezugsparameter folglich nicht verändert werden, da der Statement-Index unverändert bleiben kann. Grundvoraussetzung ist dabei immer, dass die Position des referenzierten Statements vor allen seinen referenzierenden Statements liegt. Wird kein Statement-Index angegeben, bekommt er automatisch die eigene Statement-Position. Diese ist immer 0-basiert, d.h. die Position des ersten JSON-Dicts (Statements) ist0
.name
: enthält die Angaben für System, Objekttyp und Funktion im Format<system_name>.<object_type_name>.<function_name>
old
: statische Parameter-Altwerte; Schlüssel ist der Parametername, Wert ist der alte Parameterwertnew
: statische Parameter-Neuwerte; Schlüssel ist der Parametername, Wert ist der neue Parameterwertold_ref_params
,new_ref_params
: RefParams-Anweisung zur dynamischen Parameterübergabe als JSON-Array. Enthält Dicts mit Zielreferenz, Parameter-Mapping, Positions- und Offsetangaben der Ergebnisdatensätze und JOIN-Typ / JOIN-Bedingungold_ref_idx
,new_ref_idx
: Kurzform der RefParams-Anweisung, wenn nur eine Zielreferenz ohne Parameter-Mapping benutzt wird. In diesem Fall erfolgt die Parameterübergabe automatisch, dh. es werden von allen Parametern, die das Statement der Zielreferenz zurückgibt, nur diejenigen übergeben, die in der Funktion des aktuellen Statements definiert sind. Diese Anweisung ist vor allem für Altwerte beiupdate
oderdelete
praktikabel.ref_params_join_on_val_attrs_tuple
: Tupel unqualifizierter Attributnamen für wertebasierte JOINs in RefParams-Anweisungenconstraints_deferred
: Liste der Constraints, deren Validierung bis zum Transaktionsende oder bis zum Vorkommen in einer weiterenconstraints_immediate
-Liste aufgeschoben wird. Wird vor Beginn des Statements wirksam.constraints_immediate
: Liste der Constraints, deren Validierung sofort stattfindet. Wird nach Ende des Statements wirksam.inner_join_ref
: JOIN-Anweisungunion_join_ref
: JOIN-Anweisunganti_join_ref
: JOIN-Anweisungsemi_join_noref
: JOIN-Anweisunganti_join_noref
: JOIN-Anweisungwhen
: WHEN-Anweisung
Außer name
sind alle Schlüssel je nach Kontext optional.
Die Schlüssel
inner_join_ref
,union_join_ref
,anti_join_ref
,semi_join_noref
,anti_join_noref
,when
old_ref_params
,new_ref_params
constraints_deferred
,constraints_immediate
werden nachfolgend detaillierter erklärt.
Ausgabe von Objekten relational verbundener Objekttypen mit JOIN-Anweisungen
Um relevante Ausgabedaten referenzierender oder referenzierter Objekte zu erhalten und die Datenmenge entsprechend der Objektrelationen besser einzugrenzen, können JOIN-Anweisungen eingesetzt werden. Das Verfahren arbeitet in vergleichbarer Weise zu SQL-JOINs, basierend auf den Informationen der referentiellen Datenintegrität (FK: Foreign Keys, RK: Referenced Keys) Die möglichen JOIN-Anweisungen lassen sich unterteilen nach
-
Ref: mit Zielstatement-Angabe; JOIN zwischen den beiden Objekttypen des Statements und Zielstatements per referenzierendem Constraint, oder PK-Constraint bei Self-JOINs, oder ohne Constraint bei globalen JOINs. Als JOIN-Typ der Anweisung kann
inner
oderunion
verwendet werden.inner_join_ref
: logische UND-Verknüpfung der JOINS innerhalb der Anweisung; entspricht der Schnittmengeunion_join_ref
: logische ODER-Verknüpfung der JOINS innerhalb der Anweisung; entspricht der Vereinigungsmenge
Wird
inner_join_ref
undunion_join_ref
im selben Statement kombiniert, wirken beide JOIN-Anweisungen äußerlich ebenfalls UND-verknüpft. Inner- oder Union-RefJOINs können in beiden Richtungen angewendet werden:Child joins Parent
: Statement (FK) referenziert Zielstatement (RK). In einer Union-RefJOIN-Anweisung müssen die FK-Attribute aller Constraints übereinstimmen.Parent joins Child
: Statement (RK) wird durch Zielstatement (FK) referenziert. In einer Union-RefJOIN-Anweisung müssen die RK-Attribute aller Constraints übereinstimmen.
Für Self-RefJOINs gilt immer die Richtung
Child joins Parent
. -
NoRef: ohne Zielstatement-Angabe; JOIN zwischen Statement-Objekttyp und referenzierendem Objekttyp per Foreign-Key-Constraint. Hier sind mehrere (und nur) FK-Constraints möglich, die jeweils mit
and
oderor
bewertet werden. Entspricht einerexists
bzw.not exists
-Abfrage (zum Statement-Objekt gehören bzw. gehören keine Objekte des referenzierenden Objekttyps) - Inner/Union: Übereinstimmung der Referenzattribute (Schnitt-/Vereinigungsmenge)
- Anti: Nicht-Übereinstimmung der Referenzattribute (Differenzmenge)
Ref-JOIN-Anweisung (inner
und union
)
Die Ausgabe eines Statements (‘Nachfolger’) wird mit der Ausgabe eines oder mehrerer (direkt oder indirekt) vorausgehenden Statements (‘Vorgänger’) verbunden.
Verbund (JOIN) bedeutet dabei, dass zwischen den Objekttypen dieser beiden Statements eine Relation in Form eines referenzierenden Constraints besteht.
Dabei werden nur diejenigen Objekte des Nachfolger-Statements ausgegeben,
deren referenzierbare (bzw. referenzierte) Attributwerte zu denen des Vorgänger-Statements passen.
Die Ausgabe des Vorgänger-Statements wird durch die JOIN-Anweisung somit nicht beeinflusst.
Der Verbund wird dabei über den Index des Vorgänger-Statements und -außer im Globalverbund- den Namen des referenzierenden Constraints
(s. Abschnitt Objekttypen) definiert.
Das Nachfolger-Statement hat dabei eine Position > 0, und dessen Funktion ist nicht datenmodifizierend.
Die Position des Vorgänger-Statements ist kleiner als der des Nachfolger-Statements.
In der Ref-JOIN-Anweisung (JSON-Dict unter inner_join_ref
oder union_join_ref
) ist <ref_sidx>
(Schlüssel) der Index des Vorgänger-Statements,
und "<referencing_constraint_name>"
(Wert zum Schlüssel) entweder der Constraint-Name, das Schlüsselwort "default"
, "self"
oder der Wert null
,
je nach Variante.
Es gibt 2 Verbundvarianten:
-
Constraint-basiert: Zwischen den Objekttypen des Vorgänger- und Nachfolger-Statements existiert ein referenzierender Constraint, der in der jeweiligen Objekttypdefinition unter
referencing
(seitens des Child-Objekttyps) oderreferenced_by
(seitens des Parent-Objekttyps) ausgewiesen ist. Der referenzierende Constraint ist immer dem Child-Objekttyp zugeordnet und gehört damit je nach JOIN-Richtung entweder zum Objekttyp- des Vorgänger-Statements (
Parent joins Child
) oder - des Nachfolger-Statements (
Child joins Parent
).
Die Reihenfolge beider Statements bzw. die Richtung des JOINS kann also nach Bedarf frei gewählt werden. Haben beide Statements denselben Objekttyp, sind beide Richtungen möglich. Standardmäßig ist die Richtung deshalb auf
Child joins Parent
festgelegt, d.h. Nachfolger referenziert Vorgänger. Die Steuerung der Richtung ist in diesem Fall (und nur in diesem) durch eine Erweiterung im Constraint-Ausdruck möglich. Syntax:"<constraint_name> as child" (Standard, dh. Child joins Parent; gleichwertig zu "<constraint_name>") "<constraint_name> as parent" (Parent joins Child)
Wenn es zwischen beiden Objekttypen mehrere referenzierende Constraints gibt, und der gewünschte (einzusetzende) Constraint mit dem Attribut
"is_join_default": false
ausgewiesen ist, muss dessen Name in der JOIN-Anweisung unterinner_join_ref
oderanti_join_ref
als Wert für"<referencing_constraint_name>"
(zum Dict-Schlüssel<ref_sidx>
) angegeben werden. Andernfalls ("is_join_default": true
) kann dessen Name durch das Schlüsselwort"default"
ersetzt werden.Im Nachfolger-Statement werden dadurch nur Objektdatensätze ausgegeben, die entsprechend des angegebenen Constraints zu Objekten des Vorgänger-Statements gehören. Die Zugehörigkeit der Objektdatensätze dieser beiden Verbund-Statements wird je nach JOIN-Operator über die Wertegleichheit/Zuordbarkeit der jeweiligen (Objekttyp-)Attribute des referenzierenden Constraints und des referenzierten Constraints hergestellt. (s.a. Beispiel)
Lesezugriff des Nachfolger-Statements bei JOIN-Richtung
Parent joins Child
:Haben alle eingesetzten Constraints (des Statements) das Attribut
join_grants_read_access_from_child = true,
wird der bestehende Lesezugriff für Objekte des Vorgänger-Statements automatisch auf die zugehörigen Objekte des Nachfolger-Statements übertragen. Dadurch wird garantiert, dass letztere auch ausgegeben werden, obwohl bei deren direkter Abfrage (ohne JOIN) kein Lesezugriff bestanden hätte.
Lesezugriff des Nachfolger-Statements bei JOIN-Richtung
Child joins Parent
:Haben alle eingesetzten Constraints (des Statements) das Attribut
join_grants_read_access_from_parent = true,
wird der bestehende Lesezugriff für Objekte des Vorgänger-Statements automatisch auf die zugehörigen Objekte des Nachfolger-Statements übertragen. Dadurch wird garantiert, dass letztere auch ausgegeben werden, obwohl bei deren direkter Abfrage (ohne JOIN) kein Lesezugriff bestanden hätte.
Self-JOINs: Die Objekttypen des Vorgänger- und Nachfolger-Statements sind identisch und können mittels PK-Constraint oder, falls vorhanden, mittels FK-Constraint verbunden werden.
- Bei Angabe des Schlüsselworts
"self"
als Constraintname erfolgt der JOIN mittels PK-Constraint. Der bestehende Lesezugriff für Objekte des Vorgänger-Statements wird automatisch auf die zugehörigen Objekte des Nachfolger-Statements übertragen. - Bei Angabe eines referenzierenden Constraints sind beide Richtungen möglich, wie bereits oben erläutert.
Beispiele:
- des Vorgänger-Statements (
-
Global: Der Wert zum Dict-Schlüssel
<ref_sidx>
istnull
, da es in den beiden folgenden Varianten keinen Constraint zwischen den Objekttypen des Vorgänger- und Nachfolger-Statements gibt. Hintergrund ist, dass ein Objekttyp der Kategorie “Datensenke” (Child) mehrere Objekttypen der Kategorie “Datenquelle” (Parent) referenziert. Diese Referenzen können daher nicht statisch als Constraint hinterlegt werden, sondern müssen dynamisch (zur Laufzeit) berechnet werden.Die Varianten unterscheiden sich nach der Reihenfolge der Statements bzgl. der Kategorien der Objekttypen “Datensenke” (DS, immer Child) oder “Datenquelle” (DQ, immer Parent). Als Datenquelle werden Objekttypen bezeichnet, die Log- oder OT-Attributdaten zuordbar sind; als Datensenke solche, die die eigentlichen Log- oder OT-Attributdaten enthalten.
Im Nachfolger-Statement werden alle Datensätze ausgegeben, die entsprechend der übereinstimmenden Datenart (z.B. Log, OT-Attribut) zu Objekten des Vorgänger-Statements gehören. Die Zugehörigkeit der Objektdatensätze dieser beiden Verbund-Statements wird über die Wertegleichheit des Attributs
object_gfk
(DS-seitig) und des Attributsgpk
(DQ-seitig) hergestellt.-
Child joins Parent
:Der Objekttyp des Vorgänger-Statements (Parent) gehört zur Kategorie “Datenquelle”, und der Objekttyp des Nachfolger-Statements (Child) gehört zur Kategorie “Datensenke”. Diese Variante ist geeignet, um DQ-seitig nach Objekten zu suchen sowie deren DS-seitig zugeordnete Objekte (Log-Daten bzw. OT-Attributwert-Daten) auszugeben.
Lesezugriff des Nachfolger-Statements (Child/DS): Dieser wird automatisch von Objekten des Vorgänger-Statements auf die zugehörigen Objekte des Nachfolger-Statements vererbt.
- zu gefundenen Objekten (DQ) die zugehörigen Log-Einträge (z.B. nach Top-N) anzeigen
- zu gefundenen Objekten (DQ) die zugehörigen Objektattribute (z.B. nach Attributschlüssel oder -wert) anzeigen
-
Parent joins Child
: Der Objekttyp des Vorgänger-Statements (Child) gehört zur Kategorie “Datensenke”, und der Objekttyp des Nachfolger-Statements (Parent) gehört zur Kategorie “Datenquelle”. Diese Variante ist geeignet, um DS-seitig nach Objekten (Log-Daten bzw. OT-Attributwert-Daten) zu suchen und deren DQ-seitig zugeordnete Objekte auszugeben.Lesezugriff des Vorgänger-Statements (Child/DS): Wenn durch die Parameterbelegung der Abfrage im Vorgänger-Statement sichergestellt ist, dass diese auf Objekte genau eines Objekttyps begrenzt wird, wird der Lesezugriff für Objekte des Nachfolger-Statements automatisch auf die zugehörigen Objekte des Vorgänger-Statements angewendet. Ansonsten ist für den Objekttyp des Vorgänger-Statements expliziter Lesezugriff erforderlich.
- welche der gefundenen Log-Einträge (z.B. nach Zeitraum oder Kategorie oder User) sind welchen Objekten (DQ) zugeordnet
- welche der gefundenen Attribute (z.B. nach Attributschlüssel oder -wert) sind welchen Objekten (DQ) zugeordnet
-
Ref-AntiJOIN-Anweisung
Wirkt analog zur Ref-JOIN-Anweisung, mit folgenden Ausnahmen:
- Im Nachfolger-Statement werden nur Objektdatensätze ausgegeben, für die keine zugehörigen Objekte des Vorgänger-Statements existieren
- Globale JOINs sind nicht möglich,
d.h. in der Ref-AntiJOIN-Anweisung (JSON-Dict unter
anti_join_ref
) ist<ref_sidx>
(Schlüssel) der Index des Vorgänger-Statements, und"<referencing_constraint_name>"
(Wert zum Schlüssel) entweder der Constraint-Name, das Schlüsselwort"default"
oder"self"
. - Automatisch übertragener Lesezugriff wie in der Ref-JOIN-Anweisung
(über die Constraint-Attribute
join_grants_read_access_from_parent
,join_grants_read_access_from_child
bzw. über Self-JOINs) wird nicht gewährt. Es ist also immer expliziter Lesezugriff erforderlich, es sei denn, der Lesezugriff wird durch eine oder mehrere Ref-JOIN-Anweisungen im selben Statement freigegeben. Dazu müssen alle vorhandenen Ref-JOIN-Anweisungen je nach JOIN-Richtungjoin_grants_read_access_from_parent = true
bzw.join_grants_read_access_from_child = true
haben.
NoRef-SemiJOIN-Anweisung
Im Gegensatz zu den RefJOINs wird kein Ziel-Statement benötigt. Als Constraints sind nur FK-Constraints erlaubt, die den Objekttyp des aktuellen Statements referenzieren. Es werden nur Objektdatensätze ausgegeben, wenn zugehörige Objekte der referenzierenden Objekttypen existieren (entsprechend der angegebenen Boolean-Vernküpfung). NoRef-JOINs wirken daher wie eine zusätzliche Bedingung zur Eingrenzung der abgefragten Datensätze.
NoRef-AntiJOIN-Anweisung
Wirkt analog zur NoRef-SemiJOIN-Anweisung, außer dass nur Objektdatensätze ausgegeben werden, für die keine zugehörigen Objekte der referenzierenden Objekttypen existieren (entsprechend der angegebenen Boolean-Vernküpfung).
Beispiel
Bedingte Ausführung eines Statements mit der WHEN-Anweisung
Statements, die nur unter bestimmten Voraussetzungen ausgeführt werden sollen, können durch die WHEN-Anweisung gesteuert werden.
In der WHEN-Anweisung lassen sich boolean-verknüpfte Bedingungen formulieren, die von den Ergebnisdaten eines oder mehrerer Vorgänger-Statements abhängen.
Durch die Kombination datenmodifizierender Statements mit gezielt konstruierten list
-Abfragen
(hier könnte auch die Verwendung von fetch_limit
, fetch_offset
, sorting_params_list
besonders hilfreich sein)
lassen sich auf diese Weise Vorgänge nach einer Semantik wie z.B. create_if_not_exists
oder delete_if_exists
realisieren.
Die WHEN-Anweisung besteht entweder aus einem JSON-Boolean-Wert (true
oder false
) oder aus einem JSON-Dict mit den folgenden Besonderheiten:
- Das JSON-Dict stellt den äußeren Funktionsaufruf dar und hat genau einen Schlüssel. Diese äußere Funktion muss den Datentyp
boolean
zurückgeben. - Der Schlüssel ist der Funktionsname, und der Wert ist ein JSON-Array, das die Funktionsargumente enthält.
Die Boolean-Basisfunktionen
and
,or
,not
werden hier in der Präfixnotation verwendet, d.h.true or false
wird alsor(true, false)
dargestellt. Währendand
undor
mindestens 1 Argument haben, hatnot
genau 1 Argument. - Ein Funktionsargument kann wiederum ein JSON-Dict mit den gleichen Eigenschaften wie das äußere JSON-Dict sein (innere Funktion); oder konstante JSON-Daten der verbleibenden JSON-Typen ‘array’, ‘string’, ‘number’, ‘boolean’, ‘null’, je nach Kontext.
- Der Rückgabe-Datentyp der gerufenen Funktion muss mit dem Datentyp des positionalen Arguments der rufenden Funktion übereinstimmen.
In der folgenden Tabelle sind die verwendbaren Funktionen (Dict-Schlüssel) und deren Argumente zusammengestellt.
Name (Dict-Schlüssel) | Return-Datentyp | Anzahl Argumente | Position und Datentyp der Argumente | Argument-Inhalt |
---|---|---|---|---|
"and" | boolean | > 1 | boolean | |
... | ||||
"or" | boolean | > 1 | boolean | |
... | ||||
"not" | boolean | 1 | boolean | |
"executes" | boolean | 1 | json: string | Statement-Index |
"returns_data" | boolean | 1 | json: string | Statement-Index |
"returns_no_data" | boolean | 1 | json: string | Statement-Index |
"compare" | boolean | 3 oder 4 | json: string | <operator_name> |
intern | linker Operand | |||
json | rechter Operand | |||
json | Bereichs-Operand (Standard: null ) | |||
"compare" | boolean | 4 | json: string | <operator_name> |
intern | linker Operand | |||
json | rechter Operand | |||
intern | Bereichs-Operand | |||
"compare" | boolean | 3 oder 4 | json: string | <operator_name> |
json | linker Operand | |||
intern | rechter Operand | |||
json | Bereichs-Operand (Standard: null ) | |||
"compare" | boolean | 4 | json: string | <operator_name> |
json | linker Operand | |||
intern | rechter Operand | |||
intern | Bereichs-Operand | |||
"compare" | boolean | 3 oder 4 | json: string | <operator_name> |
intern | linker Operand | |||
intern | rechter Operand | |||
json | Bereichs-Operand (Standard: null ) | |||
"compare" | boolean | 4 | json: string | <operator_name> |
intern | linker Operand | |||
intern | rechter Operand | |||
intern | Bereichs-Operand | |||
"compare" | boolean | 3 | json: string | <operator_name> |
json | linker Operand | |||
json | rechter Operand | |||
"returned_row_count" | intern: integer | 1 | json: string | Statement-Index |
"returned_param_value" | intern | 2 oder 3 | json: string | Statement-Index |
json: string | <parameter_name> | |||
json: number | <object_dict_pos> (Standard: 0 ) | |||
"returned_param_value_list" | intern | 2 oder 3 | json: string | Statement-Index |
json: string | <parameter_name> | |||
json: array, null | <object_dict_pos_array> (Standard: null ) | |||
"returned_param_value_list" | intern | 2 oder 3 | json: string | Statement-Index |
json: string | <parameter_name> | |||
json: string, null | <object_dict_pos_range_literal> (Standard: null ) |
Erläuterungen
<parameter_name>
: unqualifizierter Name des Attributes, das zum Objekttyp des Statements am Statement-Index gehören muss.<operator_name>
: Name des Operators auscntl.data_type_operator.name
.<object_dict_pos>
: Dict-Position des Ergebnisdatensatzes (Object-Dict) des Bezugsstatements.- Die Position ist
0
-basiert; d.h. das erste Dict des Bezugsstatements hat die Position0
. - Negative Werte adressieren die Position vom letzten Dict aus gerechnet; d.h. das letzte Dict hat die Position
-1
, das vorletzte-2
usw. - Nicht-existierende Positionen bewirken die Rückgabe von
NULL
.
- Die Position ist
<object_dict_pos_array>
: Einzelwerte als JSON-Array der Dict-Positionen (nicht zwingend aufeinanderfolgend)- Positionswerte wie
<object_dict_pos>
null
gibt die Werte aller Positionen zurück (äquivalent zu[0,-1]
)
- Positionswerte wie
<object_dict_pos_range_literal>
: Positionsbereich (durchgehend) als Literal im Format"[lower_bound:upper_bound]"
, analog zur Array-Slice-Notation.- Sowohl
lower_bound
als auchupper_bound
dürfen leer sein, wobei dann jeweils die erste oder letzte Dict-Position gilt. - Negative Werte adressieren die Position vom letzten Dict aus gerechnet;
d.h. das letzte Dict kann durch die Position
-1
, das vorletzte durch-2
(usw.) angesprochen werden. null
gibt die Werte aller Positionen zurück (äquivalent zu"[:]"
oder"[0:-1]"
)
- Sowohl
- Der Datentyp ‘intern’ liefert je nach Kontext den Datentyp des Objekt-Attributs (Parameters). Dies muss bei der Kombination mit dem passenden Operator beachtet werden.
- Die Boolean-Logik funktioniert gemäß PostgreSQL-Dokumentation.
Beispiele
Wiederholte Ausführung eines Statements mit der RefParams-Anweisung
Aus den JSON-Dicts (RefParams-Dicts) der RefParams-Anweisung (äußere RefParams-Arrays unter "old_ref_params"
bzw. "new_ref_params"
)
wird eine interne SQL-Abfrage konstruiert,
deren Ergebnisdatensätze als Laufzeit-Parameter in einer Schleife (Loop) an die formalen Funktionsparameter des Statements übergeben werden.
Bei den Funktionen insert
oder delete
wird nur die jeweils zutreffende der RefParams-Anweisung benötigt; bei update
können beide verwendet werden.
Im letzten Fall werden die Ergebnisdatensätze beider Anweisungen durchlaufen. Gibt eine Anweisung weniger Datensätze zurück als die andere,
werden Parameterwerte der fehlenden Datensätze mit NULL bzw. dem Defaultwert, falls vorhanden, aufgefüllt.
Jedes RefParams-Dict entspricht einem Ziel- bzw. Referenzobjekttyp, adressiert durch den Statement-Index "idx": "<ref_sidx>"
.
Ist der JOIN-Typ "join_type": null
, handelt es sich um das Basis-Statement.
Die Referenzobjekttypen aller RefParams-Dicts bilden dabei einen SQL-JOIN, der nach einem einfachen Stern-Schema aufgebaut ist.
Dessen Mittelpunkt ist immer der Objekttyp des Basis-Statements.
Für die Bildung der Laufzeit-Parameter ist das Parameter-Mapping entscheidend. Gleichnamige lokale Parameter werden
entsprechend der Position des RefParams-Dicts priorisiert, wobei die höchste Position die höchste Priorität hat.
Ist ein Parameterwert NULL (nur auf SQL-Ebene, nicht auf JSON-Ebene), wird der erste nicht-null-Wert aus den vorausgehenden Positionen eingesetzt
(SQL-NULL entsteht nur bei outer
-JOIN-Typen).
Sind die Werte aller vorausgehenden Positionen ebenfalls NULL, wird der statische Parameterwert (Altwert/Neuwert durch old
/new
) eingesetzt.
Die Schleife (und damit die Funktion des aktuellen Statements) durchläuft alle Datensätze, die durch die konstruierte Abfrage zurückgegeben werden. Im einfachsten Fall sind sie identisch mit der Ausgabe eines vorigen (des referenzierten) Statements; im komplexeren Fall werden die Ausgaben verschiedener referenzierter Statements über die JOIN-Bedingung (Werte- oder Positionsgleichheit) mit dem Basis-Statement verbunden (RefParam-JOIN) und deren Parameterwerte entsprechend der JOIN-Reihenfolge priorisiert.
Die Sortierung der Loop-Datensätze entspricht der positionalen Reihenfolge der Ergebnisdatensätze aus den referenzierten Statements, wobei zuerst die Daten des Basis-Statements (unabhängig von seiner Position im RefParams-Dict) gewertet werden, danach die der übrigen Statements nach deren aufsteigender Position im RefParams-Dict.
Die Struktur eines RefParams-Dicts:
{
"idx": "<ref_sidx>",
"params": {"<param_name>": "<ref_param_name>", ...},
"pos": null | [0,1,-1] | "<pos_range_literal>",
"join_type": null | "<join_type_keyword>",
"join_on": "pos" | "val",
"join_offset_by_idx_list": ["<ref_sidx>", ...],
"join_offset_by_constant": 0
}
Erläuterungen (s.a. Schlüssel transaction_json_schema
im Versionsindex):
"idx"
: Index des referenzierten Statements"params"
: Dict des Parameter-Mappings. Schlüssel ("<param_name>"
) sind die unqualifizierten Parameternamen des lokalen Objekttyps, Werte ("<ref_param_name>"
) die des referenzierten Objekttyps."pos"
: positionale Bereichsangabe der Ergebnisdatensätze des referenzierten Statements."<pos_range_literal>"
: analog"<object_dict_pos_range_literal>"
aus der WHEN-Anweisung-
"join_type"
: JOIN-Typ, entspricht SQL-JOIN-Typen.null
steht für das Basis-Statement und muss genau einmal in allen RefParams-Dicts des aktuellen Statements vorkommen. Mögliche Werte sind:null
"inner"
"cross"
"left_outer"
"right_outer"
"full_outer"
"left_anti"
"right_anti"
"full_anti"
-
"join_on"
: JOIN-Bedingung; bewertet Positionsgleichheit (Standard) oder Wertegleichheit gegen die Ergebnisdaten des Basis-Statements. Der Wertevergleich erfolgt als Tupel-Vergleich entsprechend der Tupel-Definition inref_params_join_on_val_attrs_tuple
der beiden beteiligten Statements. Das Tupel ist ein JSON-Array, das die Attributnamen in gleicher Reihenfolge enthält. "join_offset_by_idx_list"
: Array aus Indizes der referenzierten Statements; nur bei Positionsgleichheit ("join_on": "pos"
). Deren Anzahl der Ergebnisdatensätze wird summiert, ggf. mit dem Wert ausjoin_offset_by_constant
addiert und als positionaler Offset des referenzierten Statements in die JOIN-Bedingung eingerechnet. Für den Einsatz beiouter
-JOIN-Typen vorgesehen."join_offset_by_constant"
: konstanter positionaler Offset; nur bei Positionsgleichheit ("join_on": "pos"
). Wird zum Ergebniswert ausjoin_offset_by_idx_list
(falls angegeben) addiert, ansonsten direkt als positionaler Offset des referenzierten Statements in die JOIN-Bedingung eingerechnet. Für den Einsatz beiouter
-JOIN-Typen vorgesehen.
Steuerung der Constraint-Validierung
Bei komplexen Datenmodifikationen kann es sinnvoll oder sogar unumgänglich sein, den Zeitpunkt der Constraint-Validierung über das Statement-Ende hinaus zu verschieben. Dies wird erforderlich, wenn eine sofortige Constraint-Validierung fehlschlagen und zum Transaktionsabbruch führen würde, die erfolgreiche Constraint-Validierung aber erst nach einem späteren Statement oder am Transaktionsende möglich ist. Umgekehrt kann es sinnvoll sein, die Constraint-Validierung bereits zu einem früheren Statement (vor Ende der Transaktion) zu aktivieren, um sicherzustellen, dass zur Laufzeit der dann noch nachfolgenden Statements die Constraints bereits gültig sind.
Die Constraint-Validierung ist steuerbar, wenn ein API-Constraint das Attribut is_deferrable=true
hat.
Dies kann über die Statement-Anweisungen constraints_deferred
bzw. constraints_immediate
vorgenommen werden. Beides sind Listen der Constraint-Namen,
die entweder
- vor Beginn des Statements auf
deferred
gestellt werden - nach Ende des Statements auf
immediate
gestellt werden.
Wird derselbe Constraint in beide Anweisungen bzw. Listen eines Statements gestellt, das eine RefParams-Anweisung enthält, wird die Constraint-Validierung erst nach Durchlaufen aller RefParams-Wiederholungen aktiviert. Ein wiederholtes Stellen desselben Constraints auf denselben Deferred-Status hat keine Auswirkungen.
Generischer Objekttyp
Mit dem generischen Objekttyp tmp.generic_object
lassen sich willkürlich definierte Daten in die Transaktionsumgebung importieren
(in Kombination mit der RefParams-Anweisung sinnvoll), oder auch Parameterbelegungen zur Laufzeit simulieren und testen.
Im Prinzip handelt es sich hier nur um eine einfache Echo-Funktion, die die übergebenen Daten als Antwort zurückgibt.
Dabei werden keine persistenten Daten in die Datenbank geschrieben.
Bei diesem Objekttyp gibt es im Gegensatz zu regulären Objekttypen nur eine statische Parameterdefinition:
_dict
für die Funktionencreate
undupdate
: Definition des (genau einen) Ergebnisdatensatzes (neu) als JSON-Dict._dict_list
für die Funktionlist
: Definition der Ergebnisdatensätze (alt) als JSON-Array aus Dicts.
Unterhalb dieser Ebene können die eigentlichen Nutzdaten (Ergebnisdatensätze) definiert werden.
Das Parameter-Mapping der RefParams-Anweisung übernimmt diese Umstetzung automatisch, nicht aber die Vorbelegung mittels old
oder new
.
Soll z.B. ein regulärer Objekttyp gegen den generischen Objekttyp in einem Transaktions-JSON-Dokument getauscht werden,
müssen die Parameter-Dicts des regulären Objekttyps als Parameterwert für _dict
bzw. _dict_list
des generischen Objekttyps eingesetzt werden.
Schema der Substitution:
- regulärer Objekttyp:
[
...,
{
"title": "create an object of regular type",
"name": "dns.fqdn.create",
"new": { "value": "a.b.c", "type": "domain" }
},
...
]
- generischer Objekttyp:
[
...,
{
"title": "pseudo-create an object of generic type",
"name": "tmp.generic_object.create",
"new": { "_dict": { "value": "a.b.c", "type": "domain" } }
},
...
]
Das Parameter-Mapping in der RefParams-Anweisung: fqdn
aus Statement defineData
wird nach value
in Statement modifyData
umgesetzt.
Die Umsetzung der _dict_list
-Ebene ist hier transparent.
[
{
"title": "Definition of 3 FQDNs",
"idx": "defineData",
"name": "tmp.generic_object.list",
"old": { "_dict_list": [ { "fqdn": "a.b.c" }, { "fqdn": "d.e.f" }, { "fqdn": "g.h.i" } ] }
},
{
"title": "Create the defined FQDNs. All FQDNs are of type 'domain'.",
"idx": "modifyData",
"name": "dns.fqdn.create",
"new": { "type": "domain" },
"new_ref_params": [ { "idx": "defineData", "params": { "value": "fqdn" } } ]
}
]
Unter Hinzunahme obiger Substitution zum Testen der Parameterwerte für dns.fqdn.create
via tmp.generic_object.create
erhalten wir:
[
{
"title": "Definition of 3 FQDNs",
"idx": "defineData",
"name": "tmp.generic_object.list",
"old": { "_dict_list": [ { "fqdn": "a.b.c" }, { "fqdn": "d.e.f" }, { "fqdn": "g.h.i" } ] }
},
{
"title": "Pseudo-create the defined FQDNs to see the resulting parameter values for each function call.",
"idx": "modifyData",
"name": "tmp.generic_object.create",
"new": { "_dict": { "type": "domain" } },
"new_ref_params": [ { "idx": "defineData", "params": { "value": "fqdn" } } ]
}
]
Beispiele
GET-Request
Diese Methode kann nur für nicht-datenmodifizierende Funktionen als Einzelbefehls-Aufruf verwendet werden.
Im Funktionsindex sind diese durch das Attribut is_data_manipulating
mit dem Wert false
gekennzeichnet. Die Parameterzeichenkette (query string) entspricht hierbei
der Belegung unter old
im Parameterverzeichnis des Funktionsindex.
Da die Parameterzeichenkette kein JSON-Format hat, werden die Parameterwerte nach JSON konvertiert;
d.h. der Parameterwert wird als JSON-Literal betrachtet und daraus der entsprechende JSON-Datentyp abgeleitet.
Dabei ergeben sich folgende Besonderheiten:
- Parameterwerte der JSON-Datentypen
string
odernumber
werden gleichwertig betrachtet - Parameterwerte des JSON-Datentyps
boolean
sind als Zeichenkettetrue
oderfalse
zu übergeben null
kann nicht verwendet werden, da es als eigener JSON-Datentyp existiert und keine Unterscheidung zum Typstring
möglich ist
Alle Parameterwerte haben durchweg auswählenden Charakter und werden typischerweise logisch-UND verknüpft.
Elemente in Parameterwerten des JSON-Datentyps array
werden typischerweise logisch-ODER verknüpft.
Parameternamen dürfen nur einmal in der Parameterzeichenkette vorkommen;
andernfalls werden deren Werte als Array gepackt übergeben und dadurch fälschlicherweise als Array-Literal interpretiert,
was zu unerwünschten Ergebnissen oder zur Ablehnung des Requests führen kann.
Parameterwerte, die reservierte URI-Zeichen enthalten,
müssen kodiert werden (Stichworte ‘Prozentkodierung’, ‘URL-Encoding’,
s.a. https://de.wikipedia.org/wiki/URL-Encoding).
Antwort-Datenstruktur bei fehlerfreier Transaktion
Die Antwort ist immer ein JSON-Dokument mit dem Aufbau (von außen nach innen) in den folgenden 2 Varianten, je nachdem, wie dict_mode
gesetzt ist:
-
dict_mode
=false
(Standard):- JSON-Array: Transaktionsebene; enthält die Statement-Ebene mit den JSON-Arrays der Funktions-Antworten in der Reihenfolge der Statements aus dem Request Body. Die Statement-Position ist immer 0-basiert, d.h. das erste Statement hat die Position 0 (und, falls nicht vorgegeben, den Index “0”).
- JSON-Array: Statement-Ebene; enthält die Objektebene mit den JSON-Dicts der Funktions-Antwort
- JSON-Dict: Ergebnisdatensatz (Objekt), dessen Schlüssel bzw. Keys gleichlautend zu den Attributnamen (aus der Objekttyp-Struktur) sind
-
dict_mode
=true
:- JSON-Dict: Transaktionsebene; enthält die Statement-Ebene mit den JSON-Arrays der Funktions-Antworten. Die Statements der Transaktionsebene sind entsprechend des Statement-Index des Request Body indiziert.
- JSON-Array: Statement-Ebene; enthält die Objektebene mit den JSON-Dicts der Funktions-Antwort
- JSON-Dict: Ergebnisdatensatz (Objekt), dessen Schlüssel bzw. Keys gleichlautend zu den Attributnamen (aus der Objekttyp-Struktur) sind
Antwort-Datenstruktur im Fehlerfall (Exception, Transaktionsabbruch)
Zusätzlich zum HTTP-Statuscode (4xx) wird ein JSON-Dict zurückgegeben,
dessen (einziger) Key exception
wiederum ein Dict mit der Struktur des Objekttyps wapi.exception
enthält.
Muster:
{
"exception": {
"error": {
"code": number,
"description": "text",
"details": "text"
},
"error_type": {
"code": number,
"name": "text",
"description": "text"
},
"constraint": {
"name": "text",
"description": "text"
},
"hint": "text",
"others": {},
"stacked_diag_params" {
"column": "text",
"constraint": "text",
"context": "text",
"datatype": "text",
"detail": "text",
"dml_src_table": "text",
"hint": "text",
"message": "text",
"schema": "text",
"sqlstate": "text",
"table": "text"
},
"traceback": [
{
"function": "text",
"param": {
"<param_name1>": [ { "state": "state_descr", "value": <param_value1>, ... } ],
"<param_name2>": [ { "state": "state_descr", "value": <param_value2>, ... } ],
...
}
},
...,
{
"function": "wapi_4_2.exec_ta_handler",
"param": {
"wapi.transaction_stmt.index": number
}
}
]
}
}
- Die Keys der JSON-Dicts
error
underror_type
entsprechen den gleichnamigen Objekttypen und deren Attribute im Systemcntl
. stacked_diag_params
enthält interne Informationen zur Fehlerbehebung (Debugging).constraint
mitname
unddescription
sagt verbal aus, gegen welche Bedingung verstoßen wurde.traceback
enthält eine Liste (JSON-Array) entsprechend der Funktionsaufruffolge und der jeweiligen Parameternbelegung mit Parametername und -Wert. Der letzte Eintragwapi.transaction_stmt.index
sagt aus, welches Statement der Transaktion die Exception verursacht hat.others
ist nur im Fall nicht-zuordbarer Fehler (unbehandelte Exceptions) belegt.
Indexabfragen
Die Indexabfragen erlauben es, die gültigen Wertebelegungen der jeweils
nächsten Unterebene des URI-Schemas festzustellen.
Optional kann der endende Schrägstrich / (Slash) angehängt werden, optional gefolgt vom Schlüsselwort index
;
dies hat aber keine Auswirkungen und dient nur der Rückwärtskompatibilität bzw. Lesbarkeit.
Indexabfragen sind parameterlos. Intern sind sie eine Weiterleitung
auf den entsprechenden Objekttyp im Systemdatenbereich unter /wapi
.
Für die 4 Unterebenen gilt folgendes allgemeines Schema:
Versionsindex : <BASE-URI>
Systemindex : <BASE-URI>/<vmajor>.<vminor>
Objekttypindex: <BASE-URI>/<vmajor>.<vminor>/<sys>
Funktionsindex: <BASE-URI>/<vmajor>.<vminor>/<sys>/<objtype>
Dazu die äquivalenten Systemdatenabfragen entsprechend der internen Weiterleitung (außer Versionsindex):
Systemindex : <BASE-URI>/<vmajor>.<vminor>/wapi/system/list
Objekttypindex: <BASE-URI>/<vmajor>.<vminor>/wapi/object_type/list?system_list=["<sys>"]
Funktionsindex: <BASE-URI>/<vmajor>.<vminor>/wapi/function/list?system_list=["<sys>"]&object_type_list=["<objtype>"]
Abfragen der Systemdaten
Für den Systemdatenbereich ist das Spezial-System /wapi
vorgesehen.
Zugriffe auf diesen Bereich dürfen auch ohne Authentifizierung erfolgen.
Unterhalb dieses Systems sind Basis-Objekttypen für
- Systeme
- Objekttypen
- Funktionen und deren Zuordnungen zu Parametern bzw. Objekttyp-Attributen
- Objekttyp für Transaktionsaufrufe
- Objekttyp für Exceptions
definiert. Diese liefern Informationen über alle weiteren Systeme, Objekttypen und Funktionen.
Allgemeine Objekttyp-Datenstruktur
Jeder Objekttyp wird nach folgendem Schema dargestellt:
{
"attributes": {
"<attribute_name>": {
"data_type": "<api_datatype_name>",
"is_core": true | false,
"is_deprecated": true | false,
"is_nullable": true | false,
"supported_values": {
"<value>": "<value_description>"
}
}
},
"constraints": {
"<constraint_name>": {
"attributes": [ "<attribute_name>" ],
"errors": [
{
"code": <error_code>,
"type": <error_type_code>,
"description": "<error_description>",
"details": "<error_details>"
}
],
"join_grants_read_access_from_child": true | false,
"join_grants_read_access_from_parent": true | false,
"internal_name": "systeminterner Name des Constraints",
"is_deferred": true | false,
"is_deferrable": true | false,
"type": "<constraint_type>"
}
},
"do_activate_global_pk2obj": true | false,
"fq_name": "<system_name>.<object_type_name>",
"is_lang_dst": true | false,
"is_lang_src": true | false,
"is_log_dst": true | false,
"is_log_src": true | false,
"is_otattr_dst": true | false,
"is_otattr_src": true | false,
"name": "<object_type_name>",
"object_type_grants_read_access": true | false,
"referenceable": {
"<constraint_name>": {
"attributes": [ "<attribute_name>" ],
"is_deferred": true | false,
"is_deferrable": true | false,
"referenced_by": [ {"system": "<system_name>", "object_type": "<object_type_name>", "name": "<constraint_name>", "is_join_default": true | false} ],
"type": "<constraint_type>"
}
},
"referencing": {
"<constraint_name>": {
"attributes": [ "<attribute_name>" ],
"join_grants_read_access_from_child": true | false,
"join_grants_read_access_from_parent": true | false,
"is_deferred": true | false,
"is_deferrable": true | false,
"is_join_default": true | false,
"on_delete": "raise" | "cascade" | "set null" | "set default",
"references": {"system": "<system_name>", "object_type": "<object_type_name>", "name": "<constraint_name>"}
}
},
"system": "<system_name>"
}
Bedeutung der Platzhalter (Variablen)
<system_name>
: System-Name<object_type_name>
: Objekttyp-Name<attribute_name>
: Attribut-Name<api_datatype_name>
: Datentyp-Name des Attributs (Name auf API-Ebene)<json_datatype_name>
: Datentyp-Name des Attributs (Name auf JSON-Ebene), Wertebereich:- object
- array
- string
- number
- boolean
- json (allgemein; kann ein beliebiger der vorgenannten JSON-Datentypen sein)
<constraint_name>
: Constraint-Name<constraint_type>
: Constraint-Typ<value>
: erlaubter Attributwert<value_description>
: Erläuterung zu diesem Wert<error_code>
: numerischer Fehlercode<error_type_code>
: numerischer Fehlertypcode (negativ)<error_description>
: Fehlerbeschreibungstext<error_details>
: detaillierter Fehlertext
Bedeutung der Bezeichner (Konstanten)
- “system”: Name des Systems, dem der Objekttyp zugeordnet ist
- “name”: Objekttypname innerhalb eines Systems
- “fq_name”: voll qualifizierter (system-qualifizierter) Objekttypname
- “is_lang_dst”: Objekttyp ist OT-Sprachattribut-Datensenke (DS; hält die Inhalte (Texte) relationaler Objektsprachattribute)
- “is_lang_src”: Objekttyp ist OT-Sprachattribut-Datenquelle (DQ; objektseitiger Ursprung relationaler Objekttypsprachattribute)
- “is_log_dst”: Objekttyp ist Log-Datensenke (DS; hält die Inhalte der Log-Daten)
- “is_log_src”: Objekttyp ist Log-Datenquelle (DQ; objektseitiger Ursprung der Log-Daten, welche in der Log-Datensenke abgelegt werden)
- “is_otattr_dst”: Objekttyp ist OT-Attribut-Datensenke (DS; hält die Inhalte (Werte) relationaler Objektattribute)
- “is_otattr_src”: Objekttyp ist OT-Attribut-Datenquelle (DQ; objektseitiger Ursprung relationaler Objekttypattribute)
- “do_activate_global_pk2obj”: globaler Primärschlüssel ist aktiv
- “object_type_grants_read_access”: Lesezugriff auf Objekte dieses Typs gewährt
-
“constraints”: Constraints (Datenintegritäts- und Prüfbedingungen) des Objekttyps und ggf. zugeordnete Fehlermeldungen.
-
“type”: Constraint-Typ. Wertebereich:
- “U”: Schlüssel/Unique Key, referenzierbar. Es ist garantiert, dass die enthaltenen Attribute genau ein Objekt unter allen Objekten desselben Typs identifizieren. Darüber kann dieses Objekt angesprochen bzw. referenziert werden.
- “UP”: wie “U”, enthält die veränderlichen Primärattribute des Objekts (existiert genau einmal pro Objekttyp). Unterscheidungsmerkmal gegenüber “P”: die UP-Attribute sind veränderlich.
- “P”: Primärschlüssel/Primary Key (wie “U”, existiert genau einmal pro Objekttyp). Die Attribute eines Primärschlüssels sind garantiert unveränderlich, d.h. solange ein Objekt existiert, wird sich sein Primärschlüssel nicht ändern. (Unterscheidungsmerkmal gegenüber “UP”)
- “X”: Ausschlußbedingung zur Verhinderung von Duplikaten unter bestimmten Bedingungen
- “F”: Fremdschlüssel/Foreign Key, referenzierend, Merkmal der referentiellen Datenintegrität.
Die enthaltenen Attribute sind eine Bezugnahme zu denen im referenzierten Schlüssel oder Primärschlüssel.
Dabei ist garantiert, dass zu einem referenzierenden Objekt (child) ein referenziertes Objekt (parent) existiert.
Der Bezug wird über die jeweilige Reihenfolge der Attribute hergestellt,
d.h. das enthaltene (referenzierende) Attribut an einer Position ist dem referenzierten Attribut (des Schlüssels oder Primärschlüssels)
an derselben Position zugeordnet. Beide Attribute sind dabei wertgleich und nicht
null
. Ist ein Attributnull
, gilt die garantierte Bezugnahme nicht. - “FN”: Funktionsbasierte Referenz, referenzierend (aber kein Merkmal der referentiellen Datenintegrität) Die enthaltenen Attribute sind eine funktionale Bezugnahme zu denen im referenzierten Schlüssel oder Primärschlüssel.
- “C”: einfache Prüfbedingung
- “T”: Trigger (Komplexeres Prüfprogramm)
-
“join_grants_read_access_from_child”: bei Benutzung des Constraints im Statement-Verbund (RefJOIN) mit der Richtung ‘Parent joins Child’ wird der Lesezugriff seitens des Child-Objekttyps (Vorgänger-Statement) auf den Parent-Objekttyp (Nachfolger-Statement) übertragen, dh. durch den JOIN werden evtl. bestehende Einschränkungen der Leserechte des Parent-Objekttyps aufgehoben. Wirkt nur, wenn alle beteiligten Constraints ‘join_grants_read_access_from_child == true’ haben.
-
“join_grants_read_access_from_parent”: bei Benutzung des Constraints im Statement-Verbund (RefJOIN) mit der Richtung ‘Child joins Parent’ wird der Lesezugriff seitens des Parent-Objekttyps (Vorgänger-Statement) auf den Child-Objekttyp (Nachfolger-Statement) übertragen, dh. durch den JOIN werden evtl. bestehende Einschränkungen der Leserechte des Child-Objekttyps aufgehoben. Wirkt nur, wenn alle beteiligten Constraints ‘join_grants_read_access_from_parent == true’ haben.
-
“is_deferred”: Constraint ist initial zurückgestellt, dh. er wird (spätestens) am Ende der Transaktion validiert (
true
), bzw. sofort validiert (false
). Dadurch ist es möglich, die geforderte Bedingung durch verschiedene Statements innerhalb der Transaktion zu ignorieren, solange sie am Transaktionsende wieder erfüllt ist. -
“is_deferrable”: Möglichkeit, die Constraint-Validierung zurückzustellen (s.
constraints_deferred
undconstraints_immediate
im Statement-Dict) -
“is_join_default”: wird als Standard-Constraint bei JOIN-Anweisungen eingesetzt, falls das Schlüsselwort “default” angegeben wurde
- “internal_name”: systeminterner Name des Constraints; kann als Bezugnahme zur Constraint-Angabe unter
stacked_diag_params
im Exception-Objekt verwendet werden. - “errors”: JSON-Array der JSON-Dicts der zugeordneten Fehler
- “code”: Fehlernummer
- “type”: Fehlertypnummer
- “language_dict”: JSON-Dict mit den sprachenabhängigen Beschreibungstexten
-
-
“attributes”: JSON-Dict, dessen Schlüssel die Attribute des Objekttyps sind
- “data_type”: Datentyp-Name auf API-Ebene. Eine vollständige Übersicht aller Datentyp-Attribute ist im Objekttyp
cntl.data_type
zu finden. - “is_core”: eigenes, primär zugehöriges Attribut (Kern-Attribut) des Objekttyps (
true
). Es können auch Attribute anderer Objekttypen oder weitere Daten angegeben werden (false
). - “is_deprecated”: Attribut wird in neueren Versionen nicht mehr unterstützt (
true
) bzw. weiterhin unterstützt (false
). - “is_nullable”: Das Attribut darf den Wert
null
haben (true
) bzw. nicht haben (false
). - “supported_values”: erlaubte Werte für dieses Attribut. Nur vorhanden, wenn zutreffend. Unabhängig vom tatsächlichen Datentyp
muss die Darstellung des
<value>
als Text erfolgen, da JSON-Keys nur als Text dargestellt werden können.
- “data_type”: Datentyp-Name auf API-Ebene. Eine vollständige Übersicht aller Datentyp-Attribute ist im Objekttyp
- “referencing”: JSON-Dict, dessen Schlüssel die referenzierenden Constraint-Namen (child-seitig) sind
- “attributes”: JSON-Array der Attribute des bezeichneten Constraints
- “is_deferred”: Constraint ist initial zurückgestellt, dh. er wird (spätestens) am Ende der Transaktion validiert (
true
), bzw. sofort validiert (false
). - “is_deferrable”: Möglichkeit, die Constraint-Validierung zurückzustellen.
- “is_join_default”: wird als Standard-Constraint bei JOIN-Anweisungen eingesetzt, falls das Schlüsselwort “default” angegeben wurde
- “on_delete”: Aktion, die beim Löschen des referenzierten (parent-seitigen) Datensatzes ausgeführt wird. Mögliche Werte:
- “raise”: Exception werfen
- “cascade”: kaskadiert löschen (in Folge werden auch alle referenzierenden Datensätze gelöscht)
- “set null”: Fremdschlüssel aller referenzierenden Datensätze wird
null
gesetzt - “set default”: Fremdschlüssel aller referenzierenden Datensätze wird auf den internen Standardwert gesetzt
- “references”: JSON-Dict des referenzierten Constraints (parent-seitig) mit den Schlüsseln
- “name”: Constraint-Name
- “object_type”: Objekttyp-Name des Constraints
- “system”: System-Name des Objekttyps des Constraints
- “referenceable”: JSON-Dict, dessen Schlüssel die referenzierbaren Constraint-Namen sind (s. Constraint-Typ “U”, “UP” oder “P”)
- “attributes”: JSON-Array der Attribute des bezeichneten Constraints. Über die Werte dieser Attribute kann ein Objekt dieses Objekttyps eindeutig identifiziert werden.
- “is_deferred”: Constraint ist initial zurückgestellt, dh. er wird (spätestens) am Ende der Transaktion validiert (
true
), bzw. sofort validiert (false
). - “is_deferrable”: Möglichkeit, die Constraint-Validierung zurückzustellen.
- “referenced_by”: Liste der JSON-Dicts aller referenzierenden Constraints. Umgekehrte Darstellung zu “referencing”,
aber aus Sicht des referenzierten Objekttyps (parent). Ein Dict hat die Schlüssel
- “name”: Constraint-Name
- “object_type”: Objekttyp-Name des Constraints
- “system”: System-Name des Objekttyps des Constraints
- “is_join_default”: wird als Standard-Constraint bei JOIN-Anweisungen eingesetzt, falls das Schlüsselwort “default” angegeben wurde
- “type”: Constraint-Typ. Wertebereich: wie oben “type” unter “constraints”.
Allgemeine Funktions-Datenstruktur
Parameter bzw. Objekttyp-Attribute, die nicht-ausführbaren Funktionen zugeordnet sind, sind nur im Objekttypindex, aber nicht im Funktionsindex sichtbar. Jede ausführbare Funktion eines Objekttyps wird nach folgendem Schema dargestellt:
{
"fq_name": "<system_name>.<object_type_name>.<function_name>",
"is_data_manipulating": true | false,
"is_executable": true | false,
"is_returning": true | false,
"name": "<function_name>",
"object_type": "<object_type_name>",
"parameters": {
"<parameter_name>": {
"data_type": "<api_datatype_name>",
"is_deprecated": true | false,
"new": {
"data_default": <default_value>,
"is_nullable": true | false,
"is_required": true | false
},
"old": {
"data_default": <default_value>,
"is_nullable": true | false,
"is_required": true | false
},
"supported_values": {
"<value>": "<value_description>"
}
}
},
"system": "<system_name>"
}
Bedeutung der Platzhalter (Variablen)
<system_name>
: System-Name<object_type_name>
: Objekttyp-Name<function_name>
: Funktions-Name<parameter_name>
: Parameter-Name (bei Gleichnamigkeit zu Objekttyp-Attributnamen sind beide identisch)<api_datatype_name>
: Datentyp-Name des Attributs (Name auf API-Ebene)<json_datatype_name>
: Datentyp-Name des Attributs (Name auf JSON-Ebene), Wertebereich:- object
- array
- string
- number
- boolean
- json (allgemein; kann ein beliebiger der vorgenannten JSON-Datentypen sein)
<value>
: erlaubter Parameterwert<value_description>
: Erläuterung zu diesem Wert<default_value>
: Standardwert. Wird automatisch eingesetzt, wenn nichtnull
und wenn der Parameter in der jeweiligen Belegung nicht angegeben wurde.
Bedeutung der Bezeichner (Konstanten)
- “system”: Name des Systems, dem der Objekttyp der Funktion zugeordnet ist
- “object_type”: Name des Objekttyps der Funktion
- “fq_name”: voll qualifizierter (system- und objekttyp-qualifizierter) Funktionsname
- “is_data_manipulating”: modifizierende/datenschreibende Funktion (
true
) oder nur-datenlesende Funktion (false
) - “is_executable”: Funktion ist ausführbar und kann damit in einer Transaktion angewendet werden
- “is_returning”: Funktion ist rückgabefähig, d.h. sie kann eine nicht-leere Antwort zurückgeben
- “name”: Funktionsname innerhalb eines Systems und Objekttyps
- “parameters”: JSON-Dict, dessen Schlüssel die Funktionsparameter sind. Bei Gleichnamigkeit zu einem Attribut des Objekttyps entspricht der Parameter diesem Attribut.
- “data_type”: Datentyp-Name auf API-Ebene. Eine vollständige Übersicht aller Datentyp-Attribute ist im Objekttyp
cntl.data_type
zu finden. - “is_deprecated”: Parameter wird in neueren Versionen nicht mehr unterstützt (
true
) bzw. weiterhin unterstützt (false
). - “old”: Wertebelegung für den Zustand vor der Datenmodifikation (Altbelegung). Nur vorhanden, wenn zutreffend.
- “data_default”: Standardwert, der in dieser Belegung eingesetzt wird, falls der Parameter nicht angegeben wurde.
Erscheint nur, wenn der Standardwert nicht
null
ist. - “is_nullable”: Der Parameter darf in dieser Belegung den Wert null haben (
true
) bzw. nicht haben (false
). - “is_required”: Der Parameter muss in dieser Belegung verwendet werden (
true
) bzw. kann weggelassen werden (false
)
- “data_default”: Standardwert, der in dieser Belegung eingesetzt wird, falls der Parameter nicht angegeben wurde.
Erscheint nur, wenn der Standardwert nicht
- “new”: Wertebelegung für den Zustand nach der Datenmodifikation (Neubelegung). Nur vorhanden, wenn zutreffend.
- “data_default”: Standardwert, der in dieser Belegung eingesetzt wird, falls der Parameter nicht angegeben wurde
Erscheint nur, wenn der Standardwert nicht
null
ist. - “is_nullable”: Der Parameter darf in dieser Belegung den Wert null haben (
true
) bzw. nicht haben (false
). - “is_required”: Der Parameter muss in dieser Belegung verwendet werden (
true
) bzw. kann weggelassen werden (false
)
- “data_default”: Standardwert, der in dieser Belegung eingesetzt wird, falls der Parameter nicht angegeben wurde
Erscheint nur, wenn der Standardwert nicht
- “supported_values”: erlaubte Werte für diesen Parameter. Nur vorhanden, wenn zutreffend. Unabhängig vom tatsächlichen Datentyp
muss die Darstellung des
<value>
als Text erfolgen, da JSON-Keys nur als Text dargestellt werden können.
- “data_type”: Datentyp-Name auf API-Ebene. Eine vollständige Übersicht aller Datentyp-Attribute ist im Objekttyp
Je nach Funktion ist die Wertebelegung für old
und/oder new
definiert; mindestens aber eine davon.
Die jeweils nicht definierte Wertebelegung wird weggelassen. Für Nur-Lesefunktionen ist immer die Altbelegung definiert.
Versionsangaben
Die explizite Versionsangabe aller Zugriffe ermöglicht es, neue Features schnell einzuführen, ohne Clients, die eine bestehende Version benutzen, auszusperren oder auf deren Versionsanpassung zu warten. Die Hauptnummer wird bei umfangreichen API-Änderungen erhöht, die Anpassungen bei den meisten Clients erfordern würden; die Unternummer bei solchen, die die meisten Clients nicht betrifft.
Beide Versionsangaben (<vmajor>
, <vminor>
) sind numerisch
(natürliche Zahl). Um den Status einer Version zu kennzeichnen, gibt es
neben der numerischen Versionsangabe (Standard-Angabe) auch eine semantische Angabe.
Sie bezieht sich auf die Version der internen Schnittstelle zwischen WebAPI und der
darunterliegenden Datenbank (NetDB). Die Versionsangabe bei Requests kann nur numerisch sein.
Beispiele für den Status einer Version (semantische Versionsangaben):
alpha
: Entwicklungbeta
: Testbetrieb für begrenzten Anwenderkreis freigegebenrc
: Veröffentlichungskandidat (release candidate), abschließende Testversionrelease
: aktuelle Versionoldrelease
: veraltete Version (Vorgänger der aktuellen Version)deprecated
: nicht mehr unterstützte Version (Vorgänger der veralteten Version)
Beispiel-Szenarium für einen Versionswechsel
- vorher:
- semantische Version
beta
ist numerischer Version1.1
zugeordnet - semantische Version
release
ist numerischer Version1.0
zugeordnet - semantische Version
oldrelease
ist numerischer Version0.9
zugeordnet - semantische Version
deprecated
ist numerischer Version0.8
zugeordnet
- semantische Version
- nachher (Freigabe der
beta
-Version als neuerelease
-Version)- [NEU] semantische Version
beta
ist numerischer Version1.2
zugeordnet - semantische Version
release
ist numerischer Version1.1
zugeordnet - semantische Version
oldrelease
ist numerischer Version1.0
zugeordnet - semantische Version
deprecated
ist numerischer Version0.9
zugeordnet - [ALT] numerische Version
0.8
ist abgeschaltet und nicht mehr verfügbar
- [NEU] semantische Version