Convert JSON to XML
XML (eXtensible Markup Language) is a widely adopted standard for representing and organizing structured data. With its flexibility and human-readable syntax, XML provides a versatile solution for data interchange and storage across diverse systems and platforms. It is also used by SOAP protocol as its message format.
This guide will show you how to convert between JSON and XML SOAP using the body-transformer
plugin, which allows client to send and receive JSON data while interacting with the SOAP service.
Prerequisite(s)
- Install Docker.
- Install cURL to send requests to APISIX for validation.
- Install Java 17 for the example SOAP server.
- Follow the Getting Started tutorial to start a new APISIX instance in Docker.
Deploy an Example SOAP Server
Start an example SOAP server that exposes data from various European countries:
cd /tmp
git clone https://github.com/spring-guides/gs-soap-service.git
cd gs-soap-service/complete
./mvnw spring-boot:run
Create Transformation Templates
The transformation template mainly uses lua-resty-template syntax. See template syntax for more information.
Additionally, there are a few auxiliary functions which you can use in templates:
_escape_json()
and_escape_xml()
- used to escape special characters, such as double quotes_body
- used to access request body_ctx
- used to access context variables
Create request and response transformation templates, which are customized and to be configured in the body-transformer
plugin to instruct on how to transcode between XML and JSON:
req_template=$(cat <<EOF | awk '{gsub(/"/,"\\\"");};1' | awk '{$1=$1};1' | tr -d '\r\n'
<?xml version="1.0"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Body>
<ns0:getCountryRequest xmlns:ns0="http://spring.io/guides/gs-producing-web-service">
<ns0:name>{{_escape_xml(name)}}</ns0:name>
</ns0:getCountryRequest>
</soap-env:Body>
</soap-env:Envelope>
EOF
)
rsp_template=$(cat <<EOF | awk '{gsub(/"/,"\\\"");};1' | awk '{$1=$1};1' | tr -d '\r\n'
{% if Envelope.Body.Fault == nil then %}
{
"status":"{{_ctx.var.status}}",
"currency":"{{Envelope.Body.getCountryResponse.country.currency}}",
"population":{{Envelope.Body.getCountryResponse.country.population}},
"capital":"{{Envelope.Body.getCountryResponse.country.capital}}",
"name":"{{Envelope.Body.getCountryResponse.country.name}}"
}
{% else %}
{
"message":{*_escape_json(Envelope.Body.Fault.faultstring[1])*},
"code":"{{Envelope.Body.Fault.faultcode}}"
{% if Envelope.Body.Fault.faultactor ~= nil then %}
, "actor":"{{Envelope.Body.Fault.faultactor}}"
{% end %}
}
{% end %}
EOF
)
Configure APISIX
Create a route with body-transformer
referencing the transformation templates created previously:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "body-transformer-route",
"methods": ["POST"],
"uri": "/ws",
"plugins": {
"body-transformer": {
"request": {
"template": "'"$req_template"'",
"input_format": "json"
},
"response": {
"template": "'"$rsp_template"'",
"input_format": "xml"
}
},
"proxy-rewrite": {
"headers": {
"set": {
"Content-Type": "text/xml"
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"localhost:8080": 1
}
}
}'
❶ Set the request input format as JSON, so that the plugin will apply the JSON decoder internally.
❷ Set the response input format as XML, so that the plugin will apply the XML decoder internally.
❸ Set the Content-Type
header to text/xml
for the upstream service to respond properly.
If it is cumbersome to adjust complex text files to be valid transformation templates, you can use the base64 utility to encode the files, such as the following:
"body-transformer": {
"request": {
"template": "'"$(base64 -w0 /path/to/request_template_file)"'"
},
"response": {
"template": "'"$(base64 -w0 /path/to/response_template_file)"'"
}
}
Verify
Send a request to the route with a valid JSON body:
curl "http://127.0.0.1:9080/ws" -X POST -d '{"name": "Spain"}'
You should see a response similar to the following:
{
"status": "200",
"currency": "EUR",
"population": 46704314,
"capital": "Madrid",
"name": "Spain"
}
This shows that the JSON body sent in the request has been transformed into XML and forwarded to the upstream SOAP service, and the response body was transformed back from XML to JSON.
Next Steps
The body-transformer
plugin can also be used for transformation between YAML and JSON, or modification of the request bodies. See the plugin doc for more information.