Beispiel 1 - Wechselkurse abrufen

Beschreibung des Szenarios

In diesem Beispiel wird beschrieben, wie Sie mit einer REST-Call-Aktion Wechselkurse abrufen und in Intrexx weiter verarbeiten können.

Das Abrufen der Wechselkurse wird durch einen Klick auf die Schaltfläche "Kurse abholen" in der Applikation "Wechselkurse" ausgelöst. Anschließend werden die Kurse angezeigt. Mit jedem erneuten Klick erfolgt ein erneutes Abholen der Wechselkurse. Dies wird beispielhaft für US-Dollar (USD), Britische Pfund (GBP), Japanische Yen (JPY) und Chinesische Renminbi Yuan (CNY) durchgeführt.

Die Wechselkurse werden nach jedem Klick in eine Datengruppe geschrieben. Die Datengruppe enthält eine Spalte pro Währung , die jeweils den aktuellen Kurs enthält.

Die Applikation kann die abgefragten Kurse dann wiederum anderen Applikationen im Portal zur Verfügung stellen, beispielsweise für die Rechungsstellung.

Deutscher Zoll

Im Beispiel werden die Kurse durch eine REST-API vom Deutschen Zoll zur Verfügung gestellt. Dieser gibt täglich Wechselkurse bekannt, die bei der Bewertung von Waren zugrunde gelegt werden.

Die URL der Seite lautet: www.zoll.de/SiteGlobals/Functions/Kurse/App/KursExport.txt?view=jsonexportkurseZOLLWeb

Beschreibung der Response Daten

Die Daten werden als Json bereitgestellt. Sie haben die folgende Form:

{
   "kurse":[
      {
         "kurswert":50.96635,
         "iso3":"EGP",
         "name":"Ägyptisches Pfund"
      },
      .....
      {
         "kurswert":10.8847,
         "iso3":"MAD",
         "name":"Marokkanischer Dirham"
      },
      .....
      {
         "kurswert":1.0638,
         "iso3":"USD",
         "name":"US-Dollar"
      }
   ]
}

Das Json-Objekt enthält ein Array mit dem Namen "kurse", in dem wiederum pro Währung ein Json-Objekt eingebettet ist. Jedes dieser Objekte enthält die folgenden drei Felder:

  1. "kurswert", also den Umtauschkurs

  2. "iso3", die ISO-Bezeichnung der Währung

  3. "name", den ausgeschriebenen Namen der Währung

Response Daten verarbeiten

Grundsätzlich stellt ein REST-Call alle erhaltenen Daten im Verarbeitungskontext (SharedState) eines Prozesses (Workflows) zur Verfügung. Allerdings werden die Dabei von den jeweiligen REST-APIs jeweils unterschiedlich ausgeliefert, so dass diese von Intrexx in der Regel nicht ohne Weiteres automatisiert weiter verarbeitet werden können. Das heißt, die erhaltenen Daten müssen vor ihrer Weiterverarbeitung zunächst mit Hilfe einer Groovy-Aktion aufbereitet werden.

Applikation und Prozess erstellen

Im Folgenden wird beschrieben, wie Sie die Applikation und den Prozess mit REST-Call-Aktion erstellen. Dabei werden jeweils die zentralen Schritte beschrieben und an Hand von Screenshots illustriert.

Aufbau der Applikation

Um die Kurse speichern zu können, benötigt die Applikation eine Datengruppe, in der für die vier Währungen vier Spalten angelegt werden. Diese Spalten werden als Gleitkommazahlen angelegt, um die eingehenden Nachkommastellen korrekt vorhalten zu können.

Als Anzeige dient eine Übersichtsseite mit einer Ansichtstabelle, in der die vier Spalten plus der Zeitstempel der letzten Änderung angezeigt werden. Da der zu erstellende Prozess die Daten der Tabelle aktualisieren soll, muss zu Beginn bereits ein Eintrag vorliegen, der dann aktualisiert werden kann. Hierzu kann man mit dem Seitenassistenten eine einfache Eingabeseite für alle vier Währungen erstellen und einen Eintrag mit beliebigen Werten anlegen. Diese werden mit dem ersten REST-Call dann einfach überschrieben.

Aufbau des Prozesses

Prozess auslösen ()

Der Prozess soll durch Klick auf den Button "Kurse abholen" in der Applikation ausgelöst werden. Hierzu kann ein generischer Ereignisbehandler eingesetzt werden, der als Ereignisbehandler einen UserWorkflowEventHandler benutzt. Dieser Handler kann aus dem Portal mit dem Javascript-Befehl triggerUserWorkflowEvent() benachrichtigt werden und so den Prozess auslösen (siehe dazu unten). Beim Eintragen des Handlers wird eine GUID erzeugt, die später benötigt wird, um den Handler zu benachrichtigen.

REST-Call einrichten ()

Allgemein Der Ereignisbehandler löst nun einen REST-Call aus, der die Wechselkurse abholt. Im Beispiel wird der Call "getExchangeRates" genannt. Unter diesem Alias sind die Ergebnisse später im Verarbeitungskontext erreichbar. Da von "zoll.de" ein Json ausgeliefert wird, wird das Kontrollkästchen "JSON parsen" aktiviert. Damit wird der gelieferte Text in ein Json-Objekt umgewandelt, das dann im weiteren Verlauf bearbeitet werden kann.

Authentifizierung und Header Da die Seite keine besondere Authentifizierung benötigt, sind bei "Authentifizierung und Header" keine weiteren Einstellungen notwendig.

Request Um das Json abzuholen, wird ein GET-Request benötigt. Dieser geht zum Host zoll.de und dort auf den Pfad SiteGlobals/Functions/Kurse/App/KursExport.txt (den Teil der Adresse bis zum "?", das den Beginn der Query-Parameter anzeigt). Die Ausgabe als Json wird gesteuert, indem an den Pfad der Query-Paramater "view" auf "jsonexportkurseZOLLWeb" gesetzt wird. Dies kann direkt in die Liste der Query-Parameter eingesetzt werden.

Body Da für den Call keine Daten mitgegeben werden müssen, wird im Reiter "Body" keine Payload benötigt.

Wechselkurse extrahieren ()

In diesem Prozess-Schritt geht es darum, das erhaltene Json zu verarbeiten und ausgewählte Wechselkurse in den Verarbeitungskontext zu legen. Dafür kommt eine Groovy-Skript-Aktion zum Einsatz. Das Extrahieren der Wechselkurse wird an Hand der " JsonPath-Bibliothek" durchgeführt.

Der Call legt das erhaltene Json mit den Wechselkursen im Verarbeitungskontext unter seinem Alias als getExchangeRates.body.json ab (der Rohtext steht unter getExchangeRates.body.text zur Verfügung). Um die einzelnen Werte zu extrahieren, kann beispielsweise die JsonPath-Bibliothek benutzt werden, die für den Zugriff auf zuvor abgesetzte Rest-Calls verwendet wird. Sie enthält ein Objekt JsonPath, das über die Zeile import com.jayway.jsonpath.JsonPath; verfügbar gemacht wird.

Der Aufbau eines Json-Path wird an dieser Stelle nur skizziert. Eine ausführliche Einführung bietet die Seite der Bibliothek unter https://github.com/json-path/JsonPath oder Tutorials wie https://www.baeldung.com/guide-to-jayway-jsonpath. Im Internet gibt es zudem Seiten, die JsonPaths auswerten und prüfen, ob diese korrekt sind (z.B. https://jsonpath.com/).

Grundsätzlich besteht ein Json-Path aus einem Pfad durch das hierarchisch aufgebaute Json-Objekt. Das Symbol "$" steht zu Beginn für das gesamte Json, die einzelnen Schritte erhalten den Namen des jeweiligen Elements und werden durch einen Punkt abgetrennt. In Arrays können durch eckige Klammern ein oder mehrere Elemente ausgewählt werden. Zudem bieten JsonPaths die Möglichkeit, über "?()" Prädikate zu prüfen und so Elemente auszuwählen, die bestimmten Bedingungen genügen. Die Elemente werden dann in der Abfrage mit "@" bezeichnet, um wiederum ihre untergeordneten Elemente zu erreichen.

In unserem Fall benötigen wir zur Auswahl eines Kurses aus dem Json ($) das Array "kurse" und darin das Element, das in seinem Unterelement "iso3" den gesuchten ISO-Code enthält. Haben wir das Element gefunden, benötigen wir seinen Bestandteil "kurswert".

Damit ergibt sich der Pfad "$.kurse[].kurswert", wobei in die eckigen Klammern noch eingesetzt werden muss, welche Währung gesucht wird. Also zuerst "?()", um eine Abfrage zu formulieren, in deren Klammern dann mit "@" das jeweilige Element von "kurse" bezeichnet wird, so dass "@.iso3" bedeutet "das Feld "iso3" im aktuellen Element". Entspricht dies der Kennung der gewünschten Währung, z.B. USD ("@.iso3 == 'USD'), wird es ausgewählt. Unser Prädikat lautet damit "?(@.iso3 == 'USD')" für US-Dollar. Eingesetzt in den Pfad ergibt sich:

$.kurse[?(@.iso3 == 'USD')].kurswert, um den Wechselkurs für US-Dollar zu erreichen.

Das Objekt JsonPath steht eine Methode read() zur Verfügung, die das zu untersuchende Json nimmt sowie den Json-Pfad als String. Da "$" in Groovy als Platzhalter dient, muss es noch mit einem Backslash maskiert werden. Da die Rückgabe des REST-Calls im Verarbeitungskontext liegt, kann sie (und damit auch das Json) über das Objekt g_sharedState erreicht werden: g_sharedState.getExchangeRates.body.json

Damit kann der Aufruf wie folgt erfolgen:

JsonPath.read(g_sharedState.getExchangeRates.body.json, "\$.kurse[?(@.iso3 == 'USD')].kurswert")[0]

Das JsonPath-Objekt versucht, eine geeignete Rückgabe zu ermitteln und bietet in diesem Fall ein Array mit nur einem Wert (dem Wechselkurs) an. Da das Array selbst aber nicht benötigt wird, sondern nur der Wert darin, kann entsprechend der üblichen Zählung ab 0 für den ersten Wert mit [0] auf diesen zugegriffen werden.

Das Ergebnis kann dann wiederum im Verarbeitungskontext gespeichert werden. Dazu kann die gleiche Punkt-Schreibweise wie zum Auslesen benutzt werden: g_sharedState.usd legt also einen Platz an, an dem der Wechselkurs für USD im Verarbeitungskontext gespeichert werden kann. Er ist danach unter dem Namen "usd" abrufbar. Für die anderen Werte kann analog verfahren werden:

g_sharedState.usd = JsonPath.read(g_sharedState.getExchangeRates.body.json, "\$.kurse[?(@.iso3 == 'USD')].kurswert")[0];

Im Folgenden finden Sie das Groovy-Skript mit den Angaben zu Json-Path.

// JsonPath-Bibliothek importieren, um Daten aus dem Json im Verarbeitungskontext zu extrahieren

import com.jayway.jsonpath.JsonPath;

// Wechselkurse anhand des ISO3-Codes aus dem Json wählen und im Verarbeitungskontext ablegen
//
// Struktur des Json-Pfads:
// $.kurse[?(@.iso3 == 'GBP')].kurswert
// ^   ^           ^               ^
// |   |           |               Darin das interessierende Feld "kurswert"
// |   |           Abfrage: im Objekt aus der Liste "kurse" soll der Eintrag bei "iso3" dem Wert "GPB" entsprechen
// |   Referenz auf das untergeordnete "kurse"-Objekt
// Referenz auf das Json-Objekt
//
// Anmerkung: Im String für JsonPath.read() muss $ mit \ maskiert werden, da es
// in Groovy sonst als Platzhalter interpretiert wird
//
// Die JsonPath.read()-Abfrage liefert ein Array mit nur einem Eintrag zurück (dem Kurswert), dieser wird mit [0] erfasst

// Im Verarbeitungskontext (shared state) werden vier Objekte angelegt für USD, GBP, JPY und CNY
g_sharedState.usd = JsonPath.read(g_sharedState.getExchangeRates.body.json, "\$.kurse[?(@.iso3 == 'USD')].kurswert")[0];
g_sharedState.gbp = JsonPath.read(g_sharedState.getExchangeRates.body.json, "\$.kurse[?(@.iso3 == 'GBP')].kurswert")[0];
g_sharedState.jpy = JsonPath.read(g_sharedState.getExchangeRates.body.json, "\$.kurse[?(@.iso3 == 'JPY')].kurswert")[0];
g_sharedState.cny = JsonPath.read(g_sharedState.getExchangeRates.body.json, "\$.kurse[?(@.iso3 == 'CNY')].kurswert")[0];

Werte in eine Datengruppe eintragen ()

Im letzten Schritt sollen die vier Werte im Verarbeitungskontext in die Datengruppe der Applikation gespeichert werden. Dies kann mit einer Datengruppenaktion umgesetzt werden, die Werte in eine Datengruppe eintragen kann.

Da die Datengruppe der Applikation nur eine Zeile enthält, ist es nicht nötig, über einen Filter zu bestimmen, in welche Zeile die Daten geschrieben werden sollen. Stattdessen reicht es, unter "Allgemein" auszuwählen, dass die Aktion einen Datensatz ändern soll (bei "Hinzufügen würde stattdessen für jeden Abruf eine neue Zeile eingesetzt).

Unter "Zieldatengruppe" kann dann die Datengruppe der Applikation ausgewählt werden.

Der Reiter "Manipulationsmenge" enthält Angaben, welche Zeilen der Datengruppe die neuen Werte enthalten sollen. Da wir nur eine Zeile im Datensatz haben, reicht es aus, hier keinen Filter zu setzen. Die Änderung wird dann auf alle Zeilen der Datengruppe angewendet.

Die Feldzuordnung bestimmt, welche Werte in welche Spalten eingetragen werden.

Hier kann im rechten Fenster als Quelle ein Benutzerdefinierter Wert angelegt werden.

Unter "Systemwert" kann ein Wert aus dem Verarbeitungskontext geholt werden, dessen Namen (hier: die Namen der Währung aus dem Groovy-Skript) noch angegeben werden muss.

Nach der Zuordnung zu den Zielspalten (linkes Fenster) werden die Werte jedes Mal, wenn der Prozess ausgeführt wird, in der Datengruppe aktualisiert.

Applikation und Prozess verbinden

Um den Prozess durch Klick auf den Button "Kurse abholen" auslösen zu können, wird der Button mit einer Javascript-Funktion verbunden.

In den Eigenschaften des Buttons wird im Reiter "Skript" der Aufruf für eine Javascript-Funktion hinterlegt, die wir "execute()" nennen.

Diese Funktion kann dann im Javascript-Editor eingefügt werden.

Die Funktion "execute()" ruft triggerUserWorkflowEvent mit der GUID des Ereignisbehandlers auf und registriert zwei Funktionen, die ausgeführt werden, wenn der Prozess erfolgreich abgeschlossen wurde oder ein Fehler gemeldet wurde. Da sich die Seite nach dem Klick auf den Button aktualisieren und die neuen Kurse anzeigen soll, kann hier im Erfolgsfall location.reload() aufgerufen werden.

Im Folgenden finden Sie den JavaScript-Code.

function execute() {
	$.when(triggerUserWorkflowEvent('40AD0EE848B0B4765FE94A2E67E38C9DCBA8D109'))
	.done(function()
		{
			// Bei erfolgreicher Workflow-Ausführung: Seite neu laden
			location.reload();
		}
	)
	.fail(function()
		{
			// Bei fehlerhafter Workflow-Ausführung: Meldung und ggf. Fehlerbehandlung
			alert("Fehler bei der Ausführung.");
		}
	);
	return true;
}