Example 1 - Retrieving Exchange Rates
Description of the Scenario
This example describes how to use a REST call action to retrieve exchange rates and process them further in Intrexx.
To retrieve exchange rates, click the "Get Rates" button in the "Exchange Rates" application. The courses will then be displayed. Each time you click, the exchange rates are refreshed. This is done, for example, for the U.S. dollar (USD), the British pound (GBP), the Japanese yen (JPY), and the Chinese renminbi yuan (CNY).
The exchange rates are written to a data group after each click. The data set contains one column per currency, each of which contains the current exchange rate.
The application can then make the retrieved exchange rates available to other applications in the portal, for example, for billing purposes.
German Customs
In this example, the exchange rates are provided by German Customs via a REST API. It publishes daily exchange rates, which are used as the basis for valuing goods.
The URL for the page is: www.zoll.de/SiteGlobals/Functions/Kurse/App/KursExport.txt?view=jsonexportkurseZOLLWeb
Description of the Response Data
The data is provided in JSON format. They have the following 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"
}
]
}
The JSON object contains an array named "courses," which in turn contains a JSON object for each currency. Each of these objects contains the following three fields:
-
"exchange rate," that is, the conversion rate
-
"iso3," the ISO code for the currency
-
"name", the full name of the currency
Processing Response Data
In general, a REST call makes all received data available in the processing context (SharedState) of a process (workflow). However, the data is returned differently by each REST API, so Intrexx generally cannot automatically process it further without further steps. This means that the data received must first be processed using a Groovy action before it can be further processed.
Create an Application and a Process
The following section describes how to create the application and the process using a REST call action. The key steps are described and illustrated with screenshots.
Application Structure
To save the exchange rates, the application needs a data group in which four columns are created for the four currencies. These columns are created as floating-point numbers so that the decimal places in the input data can be stored correctly.
The display consists of an overview page with a table showing the four columns plus the timestamp of the last change. Since the process to be created is intended to update the data in the table, there must already be an entry present at the start that can then be updated. To do this, you can use the Page Wizard to create a simple input page for all four currencies and add an entry with any values you like. These will then simply be overwritten by the first REST call.
Process Structure
Trigger a process (
)
The process should be initiated by clicking the "Retrieve Courses" button in the application. To do this, you can use a generic event handler that uses a UserWorkflowEventHandler as its event handler. This handler can be notified from the portal using the JavaScript command ` triggerUserWorkflowEvent()` to trigger the process (see below for more information). When you register the handler, a GUID is generated, which will be needed later to notify the handler.
Set up a REST call (
)
General The event handler now triggers a REST call to retrieve the exchange rates. In the example, the call is called "getExchangeRates." The results will later be accessible under this alias in the processing context. Since "zoll.de" returns a JSON object, the "Parse JSON" checkbox is selected. This converts the supplied text into a JSON object, which can then be processed further.
Authentication and Headers Since the page does not require any special authentication, no further settings are necessary under "Authentication and Headers."
Request: A GET request is required to retrieve the JSON. This goes to the host zoll.de and, there, to the path SiteGlobals/Functions/Kurse/App/KursExport.txt (the part of the address up to the "?", which marks the start of the query parameters). To output the data as JSON, set the "view" query parameter to "jsonexportkurseZOLLWeb" in the path. This can be inserted directly into the list of query parameters.
Body Since no data needs to be included with the call, no payload is required in the "Body" tab.
Extract exchange rates (
)
This step in the process involves processing the received JSON and placing selected exchange rates into the processing context. A Groovy script action is used for this. Extracting the exchange rates is done using the "JsonPath library."
The call stores the received JSON containing the exchange rates in the processing context under its alias as ` getExchangeRates.body.json ` (the raw text is available at ` getExchangeRates.body.text `). To extract the individual values, you can use, for example, the JsonPath library, which is used to access previously made REST calls. It contains a JsonPath object, which is made available via the line ` import com.jayway.jsonpath.JsonPath; `.
The structure of a JSON-Path is only briefly outlined here. For a detailed introduction, visit the library's website at https://github.com/json-path/JsonPath or check out tutorials such as https://www.baeldung.com/guide-to-jayway-jsonpath. There are also websites that evaluate JSONPaths and check whether they are correct (e.g., https://jsonpath.com/).
Basically, a JSON path consists of a path through the hierarchically structured JSON object. The "$" symbol at the beginning represents the entire JSON; the individual steps are named after their respective elements and are separated by a period. In arrays, one or more elements can be selected using square brackets. In addition, JsonPaths allow you to use "?()" to apply predicates and thus select elements that meet specific conditions. The elements are then denoted by "@" in the query in order to access their child elements.
In our case, to select a course from the JSON ($), we need the "kurse" array and, within it, the element whose "iso3" subelement contains the ISO code we're looking for. Once we've found the element, we need its "kurswert" component.
This results in the path "$.kurse[].kurswert," where the currency being searched for must still be entered inside the square brackets. So first, use "?()" to formulate a query, and then use "@" within the parentheses to refer to the respective element of "kurse," so that "@.iso3" means "the 'iso3' field in the current element." If this matches the identifier for the desired currency, e.g., USD ("@.iso3 == 'USD'), it is selected. Our designation is therefore "?(@.iso3 == 'USD')" for the U.S. dollar. Substituting into the path yields:
$.rates[?(@.iso3 == 'USD')].rate to retrieve the exchange rate for the U.S. dollar.
The JsonPath object provides a read() method that takes the JSON to be parsed and the JSON path as a string. Since "$" acts as a placeholder in Groovy, it must be escaped with a backslash. Since the response to the REST call is part of the processing context, it (and thus the JSON) can be accessed via the g_sharedState object: g_sharedState.getExchangeRates.body.json
This means the call can be made as follows:
JsonPath.read(g_sharedState.getExchangeRates.body.json, "\$.rates[?(@.iso3 == 'USD')].rateValue")[0]
The JsonPath object attempts to determine an appropriate return value and, in this case, returns an array containing only one value (the exchange rate). However, since the array itself is not needed—only the value it contains—it can be accessed using [0], in accordance with the standard 0-based indexing for the first value.
The result can then be saved in the processing context. To do this, you can use the same dot notation as for reading the value: g_sharedState.usd thus creates a location where the exchange rate for USD can be stored in the processing context. It will then be available under the name "usd." The same procedure can be followed for the other values:
g_sharedState.usd = JsonPath.read(g_sharedState.getExchangeRates.body.json, "\$.rates[?(@.iso3 == 'USD')].rate")[0];
Below is the Groovy script with the JSON-Path specifications.
// 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];
Entering Values into a Data Group (
)
In the final step, the four values are to be saved to the application's data group within the processing context. This can be accomplished using a data group action that can enter values into a data group.
Since the application's data set contains only one row, it is not necessary to use a filter to determine which row the data should be written to. Instead, simply select the option under "General" to specify that the action should modify a record (selecting "Add" would instead insert a new row for each retrieval).
Under "Target Data Group," you can then select the application's data group.
The "Manipulation Set" tab contains information about which rows in the data group should contain the new values. Since we only have one row in the dataset, it's not necessary to set a filter here. The change is then applied to all rows in the data group.
Field mapping determines which values are entered into which columns.
Here, in the right-hand window, you can create a "Custom Value" as the source.
Under "System Value," you can retrieve a value from the processing context; its name (in this case, the name of the currency from the Groovy script) must still be specified.
After the values are mapped to the target columns (left pane), they are updated in the data group each time the process runs.
Connecting Applications and Processes
To trigger the process by clicking the "Retrieve Courses" button, the button is linked to a JavaScript function.
In the button's properties, under the "Script" tab, we define the call to a JavaScript function that we'll call "execute()".
This function can then be inserted into the JavaScript editor.
The "execute()" function calls ` triggerUserWorkflowEvent ` with the event handler's GUID and registers two functions that are executed when the process completes successfully or an error is reported. Since the page is supposed to refresh and display the new courses after clicking the button, location.reload() can be called here if the operation is successful.
Below is the 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;
}



















