Enrich mediator add payload wso2 - wso2

I used the enrich mediator to add a payload containing the name and totalnote of students
my problem that i want to replace the values ​​with the property
here is my code
<property expression="get-property('uri.var.nom')" name="uri.var.nom" scope="default" type="STRING"/>
<property expression="get-property('totalnote')" name="totalnote" scope="default" type="STRING"/>
<enrich>
<source clone="true" type="inline">
{"nom":"" ,
"note":""}
</source>
<target action="child" xpath="json-eval($)"/>
</enrich>
<enrich>
<source clone="true" property="uri.var.nom" type="property"/>
<target action="replace" xpath="json-eval($.etudiants.nom)"/>
</enrich>
<enrich>
<source clone="true" property="totalnote" type="property"/>
<target action="replace" xpath="json-eval($.etudiants.note)"/>
</enrich>
<respond/>
it doesn't work I always receive empty
{ "etudiants": { "nom": "", "note": "" }

You are placing the JSON structure at the root. As a child of $. But your structure does not contain etudiants, therefore the json-eval of $.etudiants.nom won't work.
The enrich itself works, as shown by #ycr but the message structure you assume to have is incorrect. Try logging the body after the first enrich to see what your payload looks like at that point.
Depending on your payload before the enrich try something like:
<enrich>
<source clone="true" type="inline">
{"etudiants": {
"nom":"" ,
"note":""
}
</source>
<target action="replace" type="body"/>
</enrich>
Or if you already have the 'etudiants' object maybe try adjusting the json-eval:
<enrich>
<source clone="true" type="inline">
{"nom":"" ,
"note":""}
</source>
<target action="child" xpath="json-eval($.etudiants)"/>
</enrich>
Hope this helps to clarify the situation.

The following seems to work for me. I have hardcoded the property values to test this. Also assuming the Payload before the Enrich is set as { "etudiants": { "nom": "", "note": "" }}. In the following example, I'm sending it in the request.
<?xml version="1.0" encoding="UTF-8"?>
<api context="/HelloWorld" name="HelloWorld" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<property name="uri.var.nom" scope="default" type="STRING" value="nomVal"/>
<property name="totalnote" scope="default" type="STRING" value="20"/>
<enrich>
<source clone="true" property="uri.var.nom" type="property"/>
<target xpath="json-eval($.etudiants.nom)"/>
</enrich>
<enrich>
<source clone="true" property="totalnote" type="property"/>
<target xpath="json-eval($.etudiants.note)"/>
</enrich>
<respond/>
</inSequence>
<outSequence/>
<faultSequence/>
</resource>
</api>
Request
curl --location --request POST 'http://localhost:8290/HelloWorld' \
--header 'Content-Type: application/json' \
--data-raw '{
"etudiants": {
"nom": "",
"note": ""
}
}'
Output
{
"etudiants": {
"nom": "nomVal",
"note": 20
}
}

Related

wso2 foreach loop never goes in

I'm trying to get a wso2 foreach loop to work.
<property expression="$ctx:xmlTransform"
Value of $ctx:xmlTransform :
<magasin>
<codeMagasin>20019</codeMagasin>
</magasin>
<magasin>
<codeMagasin>20020</codeMagasin>
</magasin>
<magasin>
<codeMagasin>20021</codeMagasin>
</magasin>
Loop :
<foreach expression="$ctx:xmlTransform//magasin" xmlns:ns="http://org.apache.synapse/xsd">
<sequence>
<log category="ERROR">
<property expression="tessst" name="----Test foreach loop----"/>
</log>
</sequence>
</foreach>
I'm never going inside the loop.
Any ideas ? Thanks a lot.
You need to check if you are adding the correct XPATH expression for the for loop. You can do this by adding a log mediator.
<log level="custom">
<property expression="$ctx:xmlTransform" name="----log----"/>
</log>
This need to print the following in order for the for loop to work. Otherwise there is an issue with the XPATH expression you have used.
INFO {org.apache.synapse.mediators.builtin.LogMediator} - ----log---- = <magasin>
<codeMagasin>20019</codeMagasin>
</magasin><magasin>
<codeMagasin>20020</codeMagasin>
</magasin><magasin>
<codeMagasin>20021</codeMagasin>
</magasin>
For example if you need to get the content from a request, the XPATH need to be modified as <foreach expression="$body//magasin">. I have sent the following payload from a postman request and it seems to be working for me without any issue. Therefore I am suspecting that the issue is with the XPATH expression you used.
Postman request body
<xmlTransform>
<magasin>
<codeMagasin>20019</codeMagasin>
</magasin>
<magasin>
<codeMagasin>20020</codeMagasin>
</magasin>
<magasin>
<codeMagasin>20021</codeMagasin>
</magasin>
</xmlTransform>
Proxy service
<?xml version="1.0" encoding="UTF-8"?><proxy xmlns="http://ws.apache.org/ns/synapse" name="DummyProxy" startOnLoad="true" statistics="disable" trace="disable" transports="http,https">
<target>
<inSequence>
<log level="custom">
<property expression="$body//magasin" name="----log----"/>
</log>
<foreach expression="$body//magasin">
<sequence>
<log>
<property name="----Test foreach loop----" value="tessst"/>
</log>
</sequence>
</foreach>
<respond/>
</inSequence>
</target>
<description/>
</proxy>
Maybe the problem is that "magasin" nodes are not enclosed in one parent element. Try to wrap it with some parent element (ex. box), replace body with the one with parent element and then run the loop.
<enrich>
<source type="inline" clone="true">
<ns:box xmlns:ns="http://namespace"/>
</source>
<target type="property" property="box"/>
</enrich>
<enrich>
<source clone="true" xpath="$ctx:xmlTransform"/>
<target action="child" xpath="$ctx:box"/>
</enrich>
<enrich>
<source type="property" clone="true" property="box"/>
<target action="replace" type="body"/>
</enrich>
<foreach expression="//ns:box/magasin" xmlns:ns="http://namespace">
<sequence>
<log category="ERROR">
<property expression="tessst" name="----Test foreach loop----"/>
</log>
</sequence>
</foreach>

WSO2 EI new xml tag using Enrich mediator and when xml tag takes dynamically

Is it possible to add new xml tag to xml payload using enrich mediator.
my sample payload -
<courses>
<id>181</id>
<formatted_name>Learning</formatted_name>
<score>0</score>
<status>in_progress</status>
<issued_certificate />
<from_timestamp>1626083705</from_timestamp>
<to_timestamp />
</courses>
New tag would be
<link> www.google.com </link>
I cannot use inline as the source since link is taken dynamically.
So I'm adding new tag to a payload and then property.
<payloadFactory media-type="xml">
<format>
<link xmlns="">$1</link>
</format>
<args>
<arg evaluator="xml" expression="get-property('login_link')"/>
</args>
</payloadFactory>
<property description="Get login link payload" expression="//root/*" name="login_link_xml" scope="default" type="STRING"/>
// get original payload back
<enrich description="Restore original payload">
<source clone="false" property="course_payload" type="property"/>
<target type="body"/>
</enrich>
// assign property as a new node inside the courses
<enrich>
<source clone="true" property="login_link_xml" type="property"/>
<target action="child" type ="custom" xpath="//courses"/>
</enrich>
This gives the same payload after enrich
You can do it in a bit different way. Create your 'tag' as property type OM, using xpath expresion and function: concat, with coded char
<property name="my_link" value="devintegra.com" scope="default" type="STRING"/>
<property name="linkNode"
type="OM"
expression="concat('<link>',get-property('my_link'),'</link>')"
scope="default" />
And with that property you can enrich your body:
<enrich>
<source type="property" clone="true" property="linkNode"/>
<target action="child" xpath="//courses"/>
</enrich>
That should work as you expect.

How can I know if a json body has content?

I have a filter to do some code if the body has body or not, because the enrich mediator cant work with a null body, but I dont know the expression
I tried boolean($body) but doesn't work
<filter regex="default_regex" source="boolean($body)">
<then>
<enrich>
<source clone="true" type="body"/>
<target property="payload" type="property"/>
</enrich>
</then>
<else>
<log level="full"/>
</else>
Could you update the regex to true and give it a try.
<filter regex="true" source="boolean($body)">
<then>
<enrich>
<source clone="true" type="body"/>
<target property="payload" type="property"/>
</enrich>
</then>
<else>
<log level="full"/>
</else>
And if it doesn't get the json payload, try assigning it to a property and do filter.
<property name="JsonBody" expression="json-eval($.)/>
<filter regex="true" source="boolean($ctx:JsonBody)">
<then>
<enrich>
<source clone="true" type="body"/>
<target property="payload" type="property"/>
</enrich>
</then>
<else>
<log level="full"/>
</else>
Thanks

Enriching the response array with the corresponding elements in the request array

Input request :
[
{
"id" : "1",
"make" : "NAHB"
},
{
"id" : "2",
"make" : "Honda"
},
{
"id" : "3",
"make" : "Samsung"
}
]
I am using iterate, to send each element of above array as request to a backend service( In myactual project this is not so simple service i.e. its reponse is very complex with lots of arrays and sub-arrays(child arrays)in it . for better understanding of issue I kept it like this ).
The responses of the backend service are aggregated in one soap xml by AggregateMediator.
Below is response from AggregateMediator
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<Information>
<jsonObject>
<id>3</id>
<name>Mobile</name>
<model>S8</model>
</jsonObject>
<jsonObject>
<id>2</id>
<name>Car</name>
<model>Amaze</model>
</jsonObject>
<jsonObject>
<id>1</id>
<name>Home</name>
<area>5000sqft</area>
</jsonObject>
</Information>
</soapenv:Body>
</soapenv:Envelope>
I want to enrich above response from AggregateMediator like below using input request.
i.e. I want to merge input request and output of backend service.(id is common between them.)
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<Information>
<jsonObject>
<id>3</id>
<name>Mobile</name>
<model>S8</model>
<make>Samsung</make>
</jsonObject>
<jsonObject>
<id>2</id>
<name>Car</name>
<model>Amaze</model>
<make>Honda</make>
</jsonObject>
<jsonObject>
<id>1</id>
<name>Home</name>
<area>5000sqft</area>
<make>NAHB</make>
</jsonObject>
</Information>
</soapenv:Body>
</soapenv:Envelope>
I kept input request array in a property before calling backend services and was able to access it in response flow.
but the problem is "both request and response are arrays". How could I run two foreach on two different arrays simultaneously and also match their id before updating each array element of response.
foreachTest.xml :
<?xml version="1.0" encoding="UTF-8"?>
<api context="/foreschTest" name="foreachTest" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST GET" uri-template="/hi">
<inSequence>
<log level="full"/>
<log level="custom">
<property expression="//jsonArray" name="message"/>
</log>
<property expression="//jsonArray" name="req" scope="default" type="STRING"/>
<foreach expression="//jsonArray/jsonElement" id="Loop">
<sequence>
<property expression="get-property('Loop_FOREACH_COUNTER')" name="countid" scope="default" type="STRING"/>
<!-- <enrich>
<source clone="true" property="INCOMING_REQUEST" type="property"/>
<target type="body"/>
</enrich>
<enrich>
<source clone="true" type="inline">
<id xmlns="">Y</id>
</source>
<target action="sibling" xpath="//jsonElement"/>
</enrich> -->
<!--<enrich>
<source clone="true" type="property" property="INCOMING_REQUEST"></source>
<target action="replace" type="body"></target>
</enrich> -->
<!-- Temporily commented <enrich>
<source clone="true" type="inline">
<uniqueId xmlns="">Y</uniqueId>
</source>
<target action="child" xpath="//jsonElement/data[2]"/>
</enrich>
<enrich>
<source clone="true" property="countid" type="property"/>
<target xpath="//jsonElement/data[2]/uniqueId"/>
</enrich> -->
<log level="custom">
<property expression="get-property('countid')" name="mgs7"/>
</log>
<log description="" level="custom">
<property expression="get-property('Loop_FOREACH_ORIGINAL_MESSAGE')" name="mgs5"/>
<property expression="get-property('Loop_FOREACH_COUNTER')" name="mgs6"/>
<property expression="//jsonElement" name="msg8"/>
</log>
<log description="" level="custom">
<property expression="//jsonElement/data[0]" name="msg9"/>
<property expression="//jsonElement/data[1]" name="msg10"/>
<property expression="//jsonElement/data[2]" name="msg11"/>
</log>
</sequence>
</foreach>
<iterate expression="//jsonArray/jsonElement" id="1">
<target>
<sequence>
<log level="custom">
<property name="msg2" value=""Inside iterate""/>
</log>
<log level="full"/>
<send>
<endpoint key="modifyAgrRespEP"/>
</send>
</sequence>
</target>
</iterate>
</inSequence>
<outSequence>
<property name="info" scope="default">
<Information xmlns=""/>
</property>
<aggregate id="1">
<completeCondition>
<messageCount max="-1" min="-1"/>
</completeCondition>
<onComplete enclosingElementProperty="info" expression="//jsonObject">
<log level="custom">
<property name="msg3" value=""Inside Aggr""/>
</log>
<log level="full"/>
<foreach expression="//Information/jsonObject">
<sequence>
<log level="custom">
<property name="msg4" value=""Inside Foreach""/>
</log>
<property expression="$body" name="agr" scope="default" type="STRING"/>
<log level="custom">
<property expression="get-property('agr')" name="agr"/>
</log>
<!-- <log level="full"/> -->
</sequence>
</foreach>
</onComplete>
</aggregate>
</outSequence>
<faultSequence/>
</resource>
</api>
modifyAgrRes.xml :
<?xml version="1.0" encoding="UTF-8"?>
<api context="/mod" name="modifyAgrRes" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST GET" uri-template="/aggr">
<inSequence>
<log level="custom">
<property name="message" value=""Inside Modify Service *************************""/>
</log>
<log level="custom">
<property expression="//jsonObject" name="location"/>
</log>
<switch source="//jsonObject/id">
<case regex="1">
<enrich>
<source clone="true" type="inline">
<name xmlns="">Home</name>
</source>
<target action="child" xpath="//jsonObject"/>
</enrich>
<enrich>
<source clone="true" type="inline">
<area xmlns="">5000sqft</area>
</source>
<target action="child" xpath="//jsonObject"/>
</enrich>
</case>
<case regex="2">
<enrich>
<source clone="true" type="inline">
<name xmlns="">Car</name>
</source>
<target action="child" xpath="//jsonObject"/>
</enrich>
<enrich>
<source clone="true" type="inline">
<model xmlns="">Amaze</model>
</source>
<target action="child" xpath="//jsonObject"/>
</enrich>
</case>
<case regex="3">
<enrich>
<source clone="true" type="inline">
<name xmlns="">Mobile</name>
</source>
<target action="child" xpath="//jsonObject"/>
</enrich>
<enrich>
<source clone="true" type="inline">
<model xmlns="">S8</model>
</source>
<target action="child" xpath="//jsonObject"/>
</enrich>
</case>
<default/>
</switch>
<log level="custom">
<property expression="//jsonObject" name="msg20"/>
</log>
<enrich>
<source clone="true" xpath="//jsonObject"/>
<target type="body"/>
</enrich>
<log level="full"/>
<respond/>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence/>
</resource>
</api>
Here is a high-level answer; I guess you can work the details out for yourself:
Copy the input ($body) to a new property (inputBody) at the
beginning
Transform $ctx:inputBody to XML - see this URL for an example:
https://docs.wso2.com/display/ESB481/Sample+440%3A+Converting+JSON+to+XML+Using+XSLT
Do all intermediate processing steps
Loop through the $ctx:inputBody property, and for each row,
Get the /id (currentId) and /make (currentMake) into new properties
Use the Enrich mediator to add a child
/Information/jsonObject[id=$ctx:currentId]/make with value set to
$ctx:currentMake
Convert back to JSON if necessary.
I hope that helps.

Preserve the original payload when calling a web service

I am struggling to figure out how to preserve a payload so that it is available after calling a web service within a sequence.
For example in the following sequence, after the “call” mediator fires the payload changes to what has been returned by the web service.
What I am looking to do is to enrich the original payload with the data that has been returned from the web service call.
All help is very much appreciated.
<log level="full"/>
<payloadFactory media-type="xml">
<format>
<Flight xmlns="">
<location_id>$1</location_id>
<FlightDistance/>
<Aircraft>
<AircraftAbbr/>
<LandingDistance/>
<TakeoffDistance/>
<AircraftRange/>
<AirframeHours/>
</Aircraft>
<Runways>
<Airport/>
</Runways>
</Flight>
</format>
<args>
<arg evaluator="xml" expression="get-property('OriginAirport')"/>
</args>
</payloadFactory>
<log level="full">
<property expression="get-property('OriginalPayload')" name="OriginalPayload"/>
</log>
<call blocking="true" description="">
<endpoint key="GetRunways"/>
</call>
<foreach expression="//d:Entries/d:Entry" id="feid" xmlns:d="http://ws.wso2.org/dataservice">
<sequence>
<log description="" level="full">
<property name="marker" value="marker"/>
</log>
<property expression="$body/Entry/runway_length" name="RunwayLength" scope="default" type="STRING"/>
<enrich>
<source clone="true" property="RunwayLength" type="property"/>
<target action="child" property="RunwayLength" type="property"/>
</enrich>
<log>
<property expression="get-property('RunwayLength')" name="PropertyValue"/>
</log>
</sequence>
</foreach>
use enrich mediator and store the payload in to property
<enrich>
<source type="body"/>
<target type="property" property="REQUEST_PAYLOAD"/>
</enrich>
https://docs.wso2.com/display/ESB481/Enrich+Mediator
To complete #Jenananthan answer:
Store original payload in a property
Call the webservice
Restore the original payload to body:
<enrich>
<source clone="false" type="property" property="ORIGINAL_PAYLOAD"/>
<target action="replace" type="body"/>
</enrich>