Call Web Service

Das Modul "Call Web Service" liest Daten von einem Webservice und schreibt sie in eine Tabelle in der Zieldatenbank. Die SQL-Webabfrage und die Konvertierung des Ergebnisses werden vom datasqill Entwickler über die GUI definiert.

Name Bedeutung
Modul Call Web Service
Modulklasse DsModWebServiceClient
Typ Java
Zweck Übertragen der Daten zwischen einem Webservice und einer Datenbank
Transformationscode SQL Abfrage auf das Ergebnis vom Web Service
Quellen Web-Request (GET, POST, PUT, PATCH; DELETE ohne Body) oder URL-Abfrage (GET)
Ziele Tabellen in der Datenbank

Beschreibung

Das Modul "Call Web Service" schickt einen Request (bzw. eine Anfrage in der URL) an einen Webservice und stellt das vom Webserver zurück gelieferte Ergebnis einer SQL-Abfrage zur Verfügung, die die Antwort überarbeitet. Das Ergebnis der SQL Abfrage wird in die Zieltabelle geschrieben.

Im Gegensatz zu Modulen die innerhalb einer Datenbank operieren, werden in diesem Modul die Daten vom Webservice gelesen und in die Zieldatenbank geschrieben.

Das folgende einfache Beispiel zeigt, wie man mit Hilfe des Moduls von der Europäischen Zentralbank die Wechselkurse zwischen Euro und US$, Britischem Pfund und Japanasiche Yen ab dem 15.05.2009 lädt. Die Abfrage wird in der URL mit angegeben.

Die URL im Objekt sieht folgendermaßen aus:

M.USD+GBP+JPY.EUR.SP00.A?updatedAfter=2009-05-15T14:15:00

Nun die verwendete SQL-Abfrage (die die Daten nicht weiter interpretiert):

SELECT r.ws_response
  FROM ${ws_response} r

Die Variable ${ws_response} wird vom Modul mit einer Unterabfrage ersetzt, die 3 Spalten liefert. Siehe weiter unten.

Heißt das Zielschema "datasqill" und die Zieltabelle "response", generiert das Modul für das Einfügen in die Zieldatenbank folgendes SQL:

INSERT INTO datasqill.response (ws_response) VALUES(?)

Wie im Beispiel zu erkennen, müssen die Spaltennamen der Zieltabelle als Aliase angegeben werden, wenn die Quellspalten anders heißen.

Datenquellen

Die Quelle des Moduls ist ein Webservice-Objekt. Bei GET-Abfragen müssen in der angegebenen URL die Abfrageparameter mit angegeben werden. In der URL können Variablen aus der Loop Query (falls angegeben) verwendet werden.

HTTP-Methode und SOAPAction (Webservice-Objekt)

Die HTTP-Methode wird in dieser Reihenfolge ermittelt:

  1. Feld Partition des Webservice-Quellobjekts (falls nicht leer).
  2. Keyfile-Parameter method (siehe unten).
  3. Feld User des Connection-Eintrags (Legacy-Fallback; vor Version 4.01 wurde die Methode dort gespeichert).
  4. Standard POST.

Unterstützt werden GET, POST, PUT, PATCH und DELETE. POST, PUT und PATCH übermitteln den unter WS Request konfigurierten Inhalt als Request-Body (mit Zeichensatz aus der Connection). DELETE sendet keinen Request-Body. GET nutzt Abfrageparameter aus der URL und aus der Request-Parameterliste der Connection.

Soll eine SOAPAction mitgesendet werden, wird sie im Feld Owner des Webservice-Quellobjekts eingetragen. Ist dieser Wert nicht leer, setzt das Modul den HTTP-Header SOAPAction entsprechend.

Bei aktiver Loop Query können Variablen aus der Schleife in der aufgelösten URL, im WS Request, im Request header sowie in den effektiven Zeichenketten für HTTP-Methode und SOAPAction (nach der obigen Auflösung) ersetzt werden.

Der verwendete Webservice muss über die datasqill GUI im grafischen Datenmodell mit dem Eingang des Moduls verbunden werden.

Datenziel

Das Ziel des Moduls ist eine einzelne Tabelle. Für diese muss der datasqill Laufzeit-Benutzer Schreibrechte besitzen.

Die Zieltabelle muss mit Hilfe der datasqill GUI im grafischen Datenmodell mit dem Ausgang des Moduls verbunden werden.

SQL Abfrage (Inhalt der Transformation)

In der angegebenen Abfrage wird die Variable ${ws_response} durch eine (datenbankabhängige) Unterabfrage ersetzt. Beispiel für Postgres:

(SELECT a ws_request, b ws_response, c http_code)

Wobei a mit dem versendeten Request, b mit dem erhaltenen Ergebnis und c mit dem Status Code vom Webaufruf ersetzt ist.

Das effektive SQL sieht für das obige Beispiel folgendermaßen aus:

SELECT r.ws_response
  FROM (SELECT a ws_request, b ws_response, c http_code) r

Attribute

Query for Loop

Hier kann ein Select Statement angegeben werden. Die Query wird in der Zieldatenbank ausgeführt. Die Spalten, die von der Loop Query zurückkehren, können als Variablen in der Haupt-Query und in der URL verwendet werden. Pro Zeile in der Loop Query wird einmal der Webservice aufgerufen. Loop Queries mit großen Ergebnismengen können die Laufzeit stark erhöhen.

WS Request

Bei POST, PUT und PATCH wird hier der zu übertragende Request-Body angegeben. Das Format entspricht dem, was der Webservice erwartet (URL-encoded, JSON, XML, ...). Im Request können Variablen aus der Loop Query (falls angegeben) verwendet werden. Bei GET und DELETE wird dieser Inhalt nicht als Body gesendet (GET nutzt URL bzw. Query-Parameter; DELETE sendet keinen Body).

Request header

"Request header" erlaubt die Definition von Headerfelder, die beim Webservice Aufruf mitgegeben werden sollen. Die Definition erfolgt mit einem einfachen Json:

{
    "header1": "value1",
    "header2": "value2
}

Variablen aus der Loopquery können verwendet werden, um Header-Keys und -Values zu ersetzen.

Truncate Before

Wenn das boolsche Attribut Truncate Before aktiviert ist, dann wird die Tabelle vorher komplett geleert. Wenn die Zieldatenbank einen datasqill Trigger für TRUNCATE TABLE anbietet, wird dieser verwendet. Ansonsten werden alle Zeilen mit dem DELETE Befehl gelöscht.

Fail on Error

Per default führt der Job zu einem Fehler, wenn der Webservice einen Fehler (Status >= 300) vom Webservice zurückliefert. Dieses kann man abschalten. In dem Fall sollte man sich den Statuscode mit speichern, um es später zu berücksichtigen.

Konfiguration eines webservies im keyfile

Im keyfile wird die Basis-URL hintelegt, sowie optional weitere Parameter für die Authentifizierung (falls notwendig).

Für den Zugriff auf den Webservice muss man eine Connection einrichten. In der Annahme, dass diese Connection die ID 11 bekommen hat, so sieht der Eintrag im keyfile folgendermaßen aus:

SQTS_DB_11 https://sdw-wsrest.ecb.europa.eu/service/data/EXR||method=GET:encoding=UTF-8|

Ein keyfile besteht aus 4 Sektionen, die mit dem Pipe "|" Symbol getrennt werden. Möchte man ein Pipe Symbol innerhalb eines Feldes verwenden, muss man es mit dem Backslash escapen.

Position Bedeutung Bemerkung
1 URL Basis URL zum Webservice
2 User Fallback für die HTTP-Methode, wenn weder das Partition-Feld des Webservice-Objekts noch der Parameter method gesetzt sind. In Implementierungen vor Version 4.01 wurde hier die Methode hinterlegt
3 Parameter Siehe Liste unten. In Implementierungen vor Version 4.01 wurde hier der verwendete Zeichensatz hinterlegt
4 Kennwort Hier wird das BASIC encripted User und Passwort paar hinterlegt

In zukünftigen Versionen wird der User und das Kennwort zur Bildung der Basic Authentifizierung verwendet.

Parameter im keyfile

Die Parameter sind immer Name/Wert Paare (Name=Wert). Mehrere Parameter werden duch einen Doppelpunkt getrennt.

Möchte man einen Doppelpunkt innerhalb eines Parameternames -oder wert verwenden, muss man ihn mit dem Backslash escapen. Dieses ist insbesondere bei der Angabe von URLs zu bedenken.

Die folgenden Parameter werden ab Version 4.01 angeboten:

Name Bedeutung Default Bemerkung
method HTTP-Methode POST GET, POST, PUT, PATCH oder DELETE; gilt, wenn das Partition-Feld des Webservice-Objekts leer ist
encoding Charcterset UTF-8 Charcterset of posted data or expected result when using GET
media_type Format text/xml Format vom zu sendenden Request, bzw. der erwarteten Antwort beim GET
https.proxyHost Proxy Host none Https Proxyadresse
https.proxyPort Proxy Port none Https Proxyport
AuthenticationUrl URL Authentifizierungs Server none Server Adresse um einen Token zu erhalten
AuthenticationMethod Authentifizierungs Methode none POST oder GET
AuthenticationRequest Authentifizierungs Request Inhalt none Bei Post wird dieser Text gesendet, um einen Token zu erhalten
AuthenticationRequestContentType Media Type none Media Type um einen Token zu erhalten
AuthenticationTokenPattern regular Expression none regular Expression um aus dem Response den Token zu extrahieren
loopDelay Delay none Mindestabstand in Millisekunden zwischen zwei Aufrufen
headerList Headerfelder none Liste von Header-Parametern als Key-Value-Paare, z.B. headerList={clientid=xyz,apikey=very-secret}
sysprops System Properties none Liste von JVM-Systemproperties als Key-Value-Paare, z.B. sysprops={javax.net.ssl.keyStore=/opt/certs/client.p12,javax.net.ssl.keyStorePassword=secret,javax.net.ssl.keyStoreType=PKCS12}

Wenn eine AuthenticationUrl angegeben ist, dann müssen auch AuthenticationMethod, AuthenticationRequest und AuthenticationTokenPattern angegeben werden.

In diesem Fall wird ein Token vom angegebenen Server angefragt und das Token wird als BEARER bei allen weiteren Webanfragen mitgesendet. Ist zusätzlich eine BASIC Authentifizierung angegeben, dann wird diese bei der Tokenabfrage zur Authentifizierung verwendet.

Wenn keine AuthenticationUrl angegeben wurde, aber eine BASIC Authentifizierung, dann wird die BASIC Authentifizierung bei jedem Serviceaufruf mit gegeben.

Ist der Parameter loopDelay vorhanden und eine valide Zahl, so wird damit der minimale Abstand zwischen zwei aufeinanderfolgenden Aufrufen sichergestellt. Käme ein nachfolgender Aufruf zu nah am vorherigen Aufruf, wird der Parameter verwendet, um eine Wartezeit zu berechnen, nach der wieder ein Aufruf erlaubt ist.

Ist

waitTime = lastInvocationTime + loopDelay - currentInvocationTime

größer als 0, so wird für diese Zeit gewartet.

GZIP-Antworten

Komprimierte Antworten werden unterstützt. Um eine komprimierte Antwort anzufordern, sende den Header Accept-Encoding: gzip (z.B. über Request header oder im Keyfile über headerList).

Wenn der Webservice mit Content-Encoding: gzip antwortet, dekomprimiert das Modul den Response-Body automatisch, bevor er in ${ws_response} gespeichert wird.

Beispiele

Laden der Wechselkurse in eine strukturierte Tabelle

Im obigen Beispiel werden die Wechselkurse derart geladen, dass die Antwort als Text in der Datenbank gespeichert wurden.

In diesem Beispiel sollen die Daten strukturiert in eine Oracle Datenbank geladen werden.

Da die EZB nur begrenzte Größen in der Antwort zulässt, werden die Wechselkurse für Dollar, Japanischen Yen und britischem Pfund mit einzeln Serviceaufrufen geladen.

Die Zieltabelle wird folgendermaßen erstellt:

CREATE TABLE datasqill.wechselkurse (
    waehrung VARCHAR2(10) NOT NULL
  , datum DATE NOT NULL
  , wechselkurs NUMBER
  , status CHAR
);

Eine Loop Query selektiert die gewünschten Währungen:

SELECT 'GBP' waehrung FROM DUAL UNION ALL
SELECT 'JPY' waehrung FROM DUAL UNION ALL
SELECT 'USD' waehrung FROM DUAL

Die angegebene URL der Webserviceabfrage enthält die Variable waehrung.

M.${waehrung}.EUR.SP00.A

Das Ergebnis der Webanfrage sieht folgendermaßen aus (ersten zwei Einträge):

<generic:Obs
    xmlns:generic="http://www.sdmx.org/resources/sdmxml/schemas/v2_1/data/generic">
    <generic:ObsDimension value="1999-01"/>
    <generic:ObsValue value="0.7029125"/>
    <generic:Attributes>
        <generic:Value id="OBS_STATUS" value="A"/>
        <generic:Value id="OBS_CONF" value="F"/>
    </generic:Attributes>
</generic:Obs>
<generic:Obs
    xmlns:generic="http://www.sdmx.org/resources/sdmxml/schemas/v2_1/data/generic">
    <generic:ObsDimension value="1999-02"/>
    <generic:ObsValue value="0.688505"/>
    <generic:Attributes>
        <generic:Value id="OBS_STATUS" value="A"/>
        <generic:Value id="OBS_CONF" value="F"/>
    </generic:Attributes>
</generic:Obs>

Die folgende Abfrage nimmt das Ergebnis der Abfrage und extrahiert mit Oracle Syntax die gewünschten Informationen aus dem XML:

SELECT ab.currency waehrung
     , TO_DATE(obs.obs_date, 'YYYY-MM') datum
     , CASE WHEN SUBSTR(obs.obs_status,1 ,1) = 'A'
         THEN TO_NUMBER(obs.obs_value, 'FM9999.99999999999999999')
       END wechselkurs
     , SUBSTR(obs.obs_status,1 ,1) status
  FROM ${ws_response} r
     , XMLTABLE(XMLNamespaces ( 'http://www.sdmx.org/resources/sdmxml/schemas/v2_1/message' AS "message"
                              , 'http://www.sdmx.org/resources/sdmxml/schemas/v2_1/common' AS "common"
                              , 'http://www.w3.org/2001/XMLSchema-instance' AS "xsi"
                              , 'http://www.sdmx.org/resources/sdmxml/schemas/v2_1/data/generic' AS "generic"
                              ),
                       '$d/message:GenericData/message:DataSet/generic:Series'
                       PASSING XMLTYPE(r.ws_response) AS "d"
                       COLUMNS dataset VARCHAR2(255 CHAR) PATH '@action'
                             , series XMLTYPE PATH '.'
                             ) ar
    , XMLTABLE(XMLNamespaces ('http://www.sdmx.org/resources/sdmxml/schemas/v2_1/data/generic' AS "generic")
               ,'$e/generic:Series' PASSING ar.series AS "e"
               COLUMNS obs XMLTYPE PATH 'generic:Obs'
                     , attributes XMLTYPE PATH 'generic:Attributes'
                     , currency VARCHAR2(255 CHAR) PATH 'generic:Attributes/generic:Value[@id="UNIT"]/@value'
               ) ab
               , XMLTABLE(XMLNamespaces ('http://www.sdmx.org/resources/sdmxml/schemas/v2_1/data/generic' AS "generic")
               ,'$f/generic:Obs' PASSING ab.obs AS "f"
               COLUMNS obs_date VARCHAR2(255 CHAR) PATH 'generic:ObsDimension/@value'
                     , obs_value VARCHAR2(255 CHAR) PATH 'generic:ObsValue/@value'
                     , obs_status VARCHAR2(255 CHAR) PATH 'generic:Attributes/generic:Value[@id="OBS_STATUS"]/@value'
               ) obs