fb
Nachrichten 12 min

Nachrichtentransformation mit WSO2 API Microgateway

Rajith Roshan
Rajith Roshan
Integration Consultant
mailbox g09b9ca3b3 1920
Scrollen

Die Transformation und Übermittlung von Nachrichten ist eine gängige Anforderung an jede Plattform für Unternehmensintegration. Die Anforderungen steigen, wenn die Integrationsplattform wächst und die Anzahl der verschiedenen Systeme, mit denen sie interagieren muss, zunimmt.

Bei einer typischen Integrationsplattform spielt das API-Management eine Schlüsselrolle bei der Bereitstellung von Transaktions- oder Streaming-Diensten/-Daten als APIs. Die Ebene der Unternehmensintegration hingegen übernimmt die Zusammenschaltung verschiedener Systeme durch Nachrichtentransformation, Protokollumschaltung usw. Verschiedene Unternehmen entscheiden sich für unterschiedliche Ansätze, um das Problem der Nachrichtentransformation zu lösen. Manche delegieren das Problem an die Integrations- oder externe Ebene, wohingegen andere es lieber auf der API-Managementebene selbst lösen. Beide Ansätze können je nach Anwendungsfall ihre Vor- und Nachteile haben.

In diesem Blog werden wir uns ein paar Ansätze für die Nachrichtentransformation mit WSO2 API Microgateway und deren Vor- und Nachteile ansehen.

WSO2 API Microgateway ist ein schlankes, cloudbasiertes API-Gateway, das für die Microservice-Architektur entwickelt wurde. Es verfügt über die eingebaute Fähigkeit, Nachrichtentransformationen mittels Interceptors durchzuführen. Wir werden uns einige Möglichkeiten ansehen, wie Interceptors verwendet werden können, um eine Transformation innerhalb der API-Ebene zu erreichen. Außerdem werden wir uns ansehen, wie wir die Transformation an ein externes System oder einen externen Dienst delegieren können.

Echo-Backend-Dienst einrichten

Betrachten wir zunächst ein Beispiel für einen Backend-Dienst. In diesem Blog verwende ich einen einfachen Echo-Netty-Server, der mit der Nutzlast der Anfrage antwortet. Dieser Dienst kann hier heruntergeladen werden[1]. Nach dem Herunterladen können Sie die JAR-Datei mit dem folgenden Befehl ausführen. Der Netty-Echo-Dienst wird auf Port 8688 gestartet

java -jar netty-http-echo-service-0.4.5.jar

Probieren Sie den Beispieldienst mit dem folgenden cURL-Befehl aus

curl -k "http://localhost:8688/echo" -X POST -d '{"foo":"val1"}' -i -v -H "Content-Type: application/json"

Microgateway-Projekt einrichten

Als Nächstes erstellen wir ein offenes API-Schema. Es definiert die API, die den Netty-Dienst über das Microgateway verfügbar macht. Diese API hat eine einzelne POST-Ressource mit dem Pfad /echo.

---
openapi: 3.0.0
servers:
- url:  "http://localhost:8688"
info:
 description: 'Dit is een voorbeeld-echoservice.'
 version: 1.0.0
 title: Echo_XML_Service
x-wso2-basePath: /transform
x-wso2-disable-security: true
paths:
 "/echo":
 post:
 summary: echoot de reactie.
 operationId: echoMethod
 responses:
        '200':
 description:  operatie geslaagd
 content:
 application/xml:{}
 application/json:{}
        '400':
 description: Ongeldige statuswaarde

Hier wird der Einfachheit halber die Erweiterung „x-wso2-disable-security“ verwendet, da wir mit dieser Eigenschaft die API über Microgateway ohne Sicherheitstoken aufrufen können.

Laden Sie als Nächstes die neuesten Versionen des Microgateway-Toolkits und der Laufzeitumgebung (3.2.X) von der Seite[2] herunter und folgen Sie den Anweisungen[3], um sie einzurichten.

Jetzt können wir das Microgateway-Projekt mit folgendem Befehl über das Toolkit initialisieren. Hier wird als Projektname „transform“ verwendet.

micro-gw init transform

Als nächstes kopieren Sie die geöffnete API-Datei in den Ordner „api_definitions“ im Projekt „transform“.

Dann bauen wir das Projekt und erstellen das Laufzeitartefakt.

Micro-GW-Build-Transformation

Schließlich können wir das gebaute Laufzeitartefakt unter Verwendung der Microgateway-Laufzeitumgebung (binär) mit dem folgenden Befehl ausführen.

./gateway <PATH_TO THE_BUILD_JAR>

Jetzt haben wir die API ohne Transformation verfügbar gemacht und sie kann mit dem folgenden Befehl über das Microgateway aufgerufen werden. Dadurch wird dieselbe JSON-Nutzlast zurückgeschickt, die wir in der Anfrage vom Netty-Back-End gesendet haben.

curl -k "https://localhost:9095/transform/echo" -X POST -d '{"foo":"val1"}' -i -v -H "Inhaltstyp: application/json"

Nehmen wir nun an, dass der Backend-Netty-Dienst die Nutzlast im XML-Format erwartet und der Client die Anfrage mit JSON-Nutzlasten sendet. Dafür sollte es also eine Transformationslogik geben, die JSON in XML umwandelt, bevor sie an das Backend gesendet wird. Wir werden uns ansehen, wie wir diese Anforderung in 3 verschiedenen Ansätzen mit API Microgateway erreichen können.

1. Innerhalb des Gateways mit Hilfe von Ballerina-Interceptors transformieren

Wir können die Transformation von JSON in XML innerhalb des Gateways mit einem Ballerina-Interceptor schreiben. Hierbei wird während des Anfrageflusses ein benutzerdefinierter Ballerina-Code eingesetzt, um die Transformation durchzuführen.

Zuerst schreiben wir den Ballerina-Code, der die JSON-Datei in XML umwandelt. Die Ballerina-Beispiele für die Version 1.2.x, die die von Microgateway 3.2.x unterstützte Ballerina-Version ist, finden Sie hier [4]. Erstellen wir nun also eine Datei mit dem Namen json_to_xml.bal (jeder beliebige Name kann verwendet werden) und platzieren den folgenden Inhalt.

import ballerina/http;
import ballerina/xmlutils;
import ballerina/log;

public function jsonToXML (http:Caller outboundEp, http:Request req) {
 json payload = checkpanic req.getJsonPayload();
 xml|error x1 = xmlutils:fromJSON(payload);
 if (x1 is xml) {
 req.setXmlPayload(x1);
 } else {
 log:printError("Error while converting json to xml", x1);
    }
}

Der Funktionsname kann hier beliebig sein, sollte aber die Parameter „http:Caller“ und „http:Request“ als Eingabeparameter für die Funktion akzeptieren, damit sie vom Gateway als Interceptorfunktion angenommen werden kann.

Kopieren Sie nun die Datei json_to_xml.bal in den interceptors-Ordner des zuvor erstellten Projekts „transform“.

Dann deklarieren wir den Interceptor in der jeweiligen API, indem wir ihn mit Hilfe der offenen API-Erweiterung „x-wso2-request-interceptors“ zur offenen API hinzufügen. Der Funktionsname sollte als Wert für die offene API-Erweiterung angegeben werden. Modifizieren Sie die offene API wie unten beschrieben. (Der rote Text zeigt die hinzugefügte offene API-Erweiterung an)

 "/echo" :
 post:
 summary: Echoes the reponse.
 operationId : echoMethod
 x-wso2-request-interceptor: "jsonToXML"

Abschließend bauen wir das Projekt und führen das gebaute Artefakt wie schon zuvor aus. Wenn wir nun die API mit demselben curl-Befehl aufrufen, können wir sehen, dass wir die Antwort im XML-Format erhalten. Hierbei wird die JSON-Nutzlast vom Microgateway in XML umgewandelt, bevor sie an das Backend gesendet wird, und der Netty-Dienst sendet die Nutzlast wie üblich als Echo zurück.

Das war doch ganz einfach, oder?

Das Hauptproblem bei diesem Ansatz, bei dem eine umfangreiche Transformationslogik am Gateway ausgeführt wird, ist jedoch der hohe Ressourcenverbrauch einer API, der sich auf die Performance aller anderen APIs auswirken kann. Das gilt vor allem dann, wenn das Gateway im geteilten Modus verwendet wird, um mehrere APIs verfügbar zu machen. Und wenn kleinere/große Versions-Upgrades des Microgateways durchgeführt werden, muss der Ballerina-Code für alle APIs aktualisiert werden, damit er mit der Ballerina-Version übereinstimmt, die von dem jeweiligen Microgateway unterstützt wird. Das kann zu einem Wartungsalptraum werden. Auch die herstellerspezifische Technologiebindung ist hier ein Thema.

2. Innerhalb des Gateways mit Hilfe von Java-Interceptors transformieren

Ähnlich wie bei Ballerina-Interceptors kann die Transformationslogik in Java entwickelt und innerhalb des Gateways selbst ausgeführt werden. Der Java-Code wird ähnlich wie bei Ballerina-Inceptors während des Anforderungsflusses innerhalb des Gateways aktiviert.

Erstellen Sie zuerst ein Java-Maven-Projekt und implementieren Sie die Java-Schnittstelle „org.wso2.micro.gateway.interceptor.Interceptor“, die die Umwandlung von JSON in XML implementiert (JsonToXML.java-Klasse).

pom.xml

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>json-to-xml-transform</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.wso2.am.microgw</groupId> <artifactId>mgw-interceptor</artifactId> <version>3.2.0</version> </dependency> </dependencies> </project>

JsonToXML.java

package org.mgw.transform; import org.json.JSONObject; import org.json.XML; import org.wso2.micro.gateway.interceptor.Caller; import org.wso2.micro.gateway.interceptor.Interceptor; import org.wso2.micro.gateway.interceptor.InterceptorException; import org.wso2.micro.gateway.interceptor.Request; import org.wso2.micro.gateway.interceptor.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.charset.StandardCharsets; public class JsonToXML implements Interceptor { private static final Logger log = LoggerFactory.getLogger("ballerina"); public boolean interceptRequest(Caller caller, Request request) { try { JSONObject payload = request.getJsonPayload(); String xml = XML.toString(payload); request.setBinaryPayload(xml.getBytes(StandardCharsets.UTF_8)); request.setContentType("application/xml"); } catch (InterceptorException e) { log.error("Error while getting json payload from request", e); } return true; } public boolean interceptResponse(Caller caller, Response response) { return true; } }

Bauen Sie das Maven-Projekt mit „mvn clean install“ und kopieren Sie die gebaute JAR-Datei in das lib-Verzeichnis des Projekts „transform“.

Bearbeiten Sie dann die geöffnete API-Datei des Projekts „transform“, um die Java-Interceptor-Klasse anstelle des Ballerina-Funktionsnamens zu deklarieren. Der Erweiterungswert sollte das Format „java:<Full_Qualified_Class_Name>“ haben (siehe roten Text im Beispiel unten).

paths:
 "/echo" :
 post:
 summary: Echoes the reponse.
 operationId : echoMethod
 x-wso2-request-interceptor: java:org.mgw.transform.JsonToXML

Bauen Sie schließlich das Projekt und führen Sie das gebaute Artefakt wie schon zuvor mit der Gateway-Laufzeitumgebung aus. Wenn Sie nun auch den JSON-Request-Body mit dem cURL-Befehl senden, wird er mit der XML-Nutzlast antworten.

Ähnlich wie bei den Ballerina-Interceptors liegt das Problem bei diesem Ansatz darin, dass eine umfangreiche Transformationslogik am Gateway ausgeführt wird, wenn es im geteilten Modus verwendet wird (mehrere APIs verfügbar machen). Dabei kann sich ein Problem mit einer API auf alle anderen APIs auswirken. Der Thread zur Verarbeitung der Anforderung benötigt möglicherweise viel Zeit für die Umwandlung, wodurch der Thread ausgelastet ist und API-Anforderungen nicht bearbeitet werden können.

Bei der Skalierung der Gateways ist auch die Verarbeitung der Transformationslogik zu berücksichtigen. Dies kann bei der Bereitstellung auf Plattformen mit automatischer Skalierung wie Kubernetes zu anormalem Skalierungsverhalten führen.

3. Transformationslogik auslagern

Bei diesem Ansatz konzentrieren wir uns auf die Ausführung der Transformationslogik über einen externen Dienst. Dies kann jeder externe Dienst wie Spring, Netty, CXF auf Tomcat oder ein Enterprise Integrator sein, der für diese Art von Transformationen entwickelt wurde.

In diesem Blog verwende ich WSO2 Micro Integrator (4.0.0), einen Enterprise Integrator, der speziell für Transformationen, Übermittlungen und andere Integrationsanforderungen entwickelt wurde.

Laden Sie den Mikrointegrator herunter (MI 4.0.0 und das Integrationsstudio (Low-Code-Tool zum Entwickeln von Integrationen) [5]

micro integrator
micro integrator

Wir entwickeln nun einen einfachen Proxy-Dienst im Developer Studio, der JSON in XML umwandelt. Eine Dokumentation zur Erstellung eines Proxy-Dienstes mit dem Integration Studio und dessen Bereitstellung im Mikrointegrator finden Sie hier[6].

Hier finden Sie die Beispielkonfiguration des Proxy-Dienstes und die Sequenz, die mit dem Integration Studio erstellt wurde, um die Umwandlung von JSON in XML durchzuführen.

Proxy-Dienst

<?xml version = "1.0" Kodierung = "UTF-8"?>
<proxy name="jsontoxml" startOnLoad="true" transports="http https" xmlns="http://ws.apache.org/ns/synapse">
<target inSequence="convert_json_to_xml">
<outSequence/>
<faultSequence/>
</target>
</proxy>

In der Sequenz

<?xml version = "1.0" Kodierung = "UTF-8"?>
<sequence name="convert_json_to_xml" trace="disable" xmlns="http://ws.apache.org/ns/synapse">
<log level="full"/>
<property name="messageType" scope="axis2" type="STRING" value="application/xml"/>
<enrich>
<source clone="false" xpath="$body/jsonObject/*"/>
<target type="body"/>
</enrich>
<respond/>
</sequence>

Hier kann die Umwandlung von JSON in XML einfach durch die Einstellung der Eigenschaft messgeType als „application/xml“ erreicht werden. WSO2 MI fügt die umgewandelte XML in das übergeordnete XML-Tag <jsonObject> ein. Der Enrich-Mediator wird verwendet, um das übergeordnete XML-Tag zu entfernen.

Sobald die Artefakte fertig sind, erstellen Sie die CAR-Datei mit dem Integration Studio und stellen die CAR-Datei im Mikrointegrator bereit. Nach der Bereitstellung kann der Proxy-Dienst mit jeder JSON-Nutzlast aufgerufen werden und antwortet mit einer Antwort im umgewandelten XML-Format.

curl -k "https://localhost:8253/services/jsontoxml" -X POST -d '{"foo":"val1"}' -i -v -H "Content-Type: application/json"

Da unsere Transformationslogik nun auf einem externen Server läuft, schreiben wir einfach einen Ballerina-Code, um diesen externen Endpunkt aufzurufen und die Logik ähnlich wie beim 1. Ansatz als Ballerina-Interceptor zu aktivieren.

Nachfolgend sehen Sie ein Codefragment des Ballerina-Interceptors, das den externen Proxy-Dienst auf dem Mikrointegrator aufruft.

import ballerina/http;
import ballerina/log;

http:Client clientEP = new ("http://localhost:8290/services/jsontoxml");

public function callMI (http:Caller outboundEp, http:Request req) {
 http:Response|error resp = clientEP->forward("/", req);
 if (resp is http:Response) {
 xml|error x1 = resp.getXmlPayload();
 if (x1 is xml) {
 req.setXmlPayload(validate(x1));
 } else {
 log:printError("Error while getting the xml payload from external transform service", x1);
        }
    }
}

function validate(xml input) returns @untainted xml {
 return input;
}

Gemäß dieser Logik leitet Microgateway die Anforderung an den Proxy-Dienst des Mikrointegrators weiter, der auf „localhost:8290/services/jsontoxml“ läuft. Dieser Aufruf erfolgt nicht-blockierend, wobei der Anforderungsthread freigegeben wird, sobald der Aufruf an den externen Endpunkt erfolgt ist.

Ähnlich wie beim 1. Ansatz definieren wir diesen Interceptor in der offenen API-Definition, damit er als Ballerina-Interceptor aktiviert wird.

paths:
 "/echo" :
 post:
 summary: Echoes the reponse.
 operationId : echoMethod
x-wso2-request-interceptor: "callMI"

Abschließend erstellen wir das Microgateway-Projekt und führen es mit der Microgateway-Laufzeitumgebung aus.

Beim Aufruf mit einer JSON-Nutzlast über cURL wird mit einer XML-Nutzlast geantwortet (die umgewandelte JSON-Nutzlast).

Dieser Ansatz eignet sich besser für jede Architektur, die umfangreiche Nachrichtentransformationen erfordert. Die Performance des Gateways und aller anderen vom Gateway bereitgestellten APIs bleibt konsistent, da die Transformationslogik keine Gateway-CPU-Zyklen benötigt. Die Architektur ist zukunftssicherer, da Sie die Flexibilität haben, eine eigene Implementierung der Transformationslogik beizubehalten, und Sie nicht an einen bestimmten Anbieter oder eine bestimmte Technologie gebunden sind. Immer wenn sich das Unternehmen für ein größeres Upgrade der API-Gateway-Ebene oder einen Wechsel von einem Anbieter zu einem anderen entscheidet, kann die vorhandene Transformationslogik verwendet werden.

Fazit

In diesem Blog habe ich versucht, eine einfache Transformationsanforderung wie die Umwandlung von JSON in XML als Beispiel zu verwenden, um die Vor- und Nachteile von drei verschiedenen Architekturmustern zu erläutern, die häufig mit WSO2 Microgateway verwendet werden. Ich hoffe, dass dieser Artikel Ihnen helfen wird, den geeignetsten und zukunftssichersten Ansatz zu finden, der den Anforderungen Ihres Unternehmens am ehesten entspricht.

[1] – https://search.maven.org/artifact/org.wso2.performance.common/netty-http-echo-service/0.4.5/jar

[2] – https://wso2.com/api-manager/api-microgateway/

[3] – https://mg.docs.wso2.com/en/latest/install-and-setup/install-on-vm/

[4] – https://ballerina.io/1.2/learn/by-example/

[5] – https://wso2.com/integration/micro-integrator/

[6] – https://ei.docs.wso2.com/en/7.2.0/micro-integrator/develop/creating-artifacts/creating-a-proxy-service/