Payload Factory exception with invalid json - wso2

If I use a payload factory to create or simply to clean the payload in case of fault, the payload factory fail with an exception.
So, in case of error, I can't manipulate the payload.
I only need to remove it for example, so the fact that is invalid for me is not influential.
Example:
<?xml version="1.0" encoding="UTF-8"?>
<api context="/DemoError" name="DemoError" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<payloadFactory media-type="json">
<format>{
"status":"OK"
}</format>
<args/>
</payloadFactory>
<loopback/>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence>
<payloadFactory media-type="json">
<format>{
"status":"KO"
}</format>
<args/>
</payloadFactory>
</faultSequence>
</resource>
</api>
In this example, if I made a call with an invalid json...
The ESB, it goes in the fault sequence (right) but when I try in the fault to clean the payload, the payload factory fail (org.apache.synapse.commons.SynapseCommonsException: Existing json payload is malformed), the worst thing is that failing the fault sequence it return http 202...very bad
I'm using WSO2 EI 6.5.0

I tried out your API. It is not failing actually. If I add a <respond/> mediator after Payload Factory mediator inside Fault Sequence, I can see that the Fault Sequence payload is returning correctly.

I reproduced the issue, it's a little bit more complex.
If I have a validator, it goes in seems to go in the fault sequence, as expected, but now, the fault sequence fail on payload factory, returning http 202.
Try this:
<?xml version="1.0" encoding="UTF-8"?>
<api context="/DemoError" name="DemoError" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="POST">
<inSequence>
<validate cache-schema="true">
<schema key="gov:custom/schema.json"/>
<on-fail>
<log level="custom">
<property name="ERROR" value="VALIDATE"/>
</log>
</on-fail>
</validate>
<payloadFactory media-type="json">
<format>{
"status":"OK"
}</format>
<args/>
</payloadFactory>
<loopback/>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence>
<log level="custom">
<property name="ERROR" value="I'M IN FAULT SEQUENCE"/>
</log>
<property name="HTTP_SC" scope="axis2" type="STRING" value="500"/>
<payloadFactory media-type="json">
<format>{
"status":"KO"
}</format>
<args/>
</payloadFactory>
<respond/>
</faultSequence>
</resource>
</api>
with the following schema:
{
"$id": "https://example.com/person.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "example",
"type": "object",
"required": [ "input"],
"properties": {
"input": {
"type": "boolean",
"description": "Input"
}
}
}
and the following input:
{
"input":xxx
}

This is related to the issue reported in [1]. Until a GA release includes the fix, the WUM updated versions will contain the fix for the EI versions including wso2ei-6.6.0.
[1]. https://github.com/wso2/product-ei/issues/2757

Related

Callout is calling a diferent endpoint

Hi i'm new in wso2 and I have 2 api's, I want to call the second one using the first, but the url that the callout mediator is using is diferente from the one I set up, resulting in error HTTPSender Unable to sendViaGet to url[http://192.168.20.1:8280/loginAPI/login/Nurse]
The code is below
Any help will be welcome
<api context="/Staff" name="StaffAPI" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET" url-mapping="/Nurse">
<inSequence>
<log level="full"/>
<callout description="" initAxis2ClientOptions="false" serviceURL="http://192.168.20.1:8280/loginAPI/login">
<source type="envelope"/>
<target key="response"/>
</callout>
<log level="custom">
<property expression="get-property('response')" name="response"/>
</log>
<send>
<endpoint key="NurseEP"/>
</send>
</inSequence>
<outSequence>
<send/>
</outSequence>
<faultSequence/>
</resource>
<api context="/loginAPI" name="LoginAPI" xmlns="http://ws.apache.org/ns/synapse">
<resource methods="GET" uri-template="/login">
<inSequence>
<payloadFactory media-type="json">
<format>{
"userName": "xxx",
"password": "xxx",
"rememberMe": true,
"fireBaseToken": "string"
}</format>
<args/>
</payloadFactory>
<cache collector="false" hashGenerator="org.wso2.carbon.mediator.cache.digest.DOMHASHGenerator" id="Token" maxMessageSize="2000" scope="per-host" timeout="5000">
<onCacheHit/>
<implementation maxSize="1000" type="memory"/>
</cache>
<send>
<endpoint key="LoginEP"/>
</send>
</inSequence>
<outSequence>
<cache collector="true" scope="per-host"/>
<send/>
</outSequence>
<faultSequence/>
</resource>
The http://192.168.20.1:8280/loginAPI/login endpoint when called on postman is valid
It seams that your serviceURL is suffixed by your api url-mapping, try to add that before callout (it has to be used in case of send mediator, not sure for callout but it looks like the same behavior) :
<property name="REST_URL_POSTFIX" scope="axis2" action="remove"/>

Call multiple sequences in paralell and merge in payloadfactory

I have an endpoint in wso2 integrator, wich receive some parameters, call some rest apis, and produce a new response.
I created a sequence for each rest api call, wich will get the properties and make the specific call. Then with a script mediator, i'm creating a new payload with the response, and putting it in a property. Example: myResponseA, myResponseB, myResponseC.
My main endpoint have an IN sequence with only a clone mediator and a loopback tag. The clone mediator have a target for each sequence described above, like:
<clone continueParent="false" sequential="true">
<target sequence="mySequenceA">
</target>
<target sequence="mySequenceB">
</target>
</clone>
<loopback />
My main endpoint have an OUT sequence with a payloadFactory and a send tag, like:
<payloadFactory media-type="json">
<format>
<![CDATA[
{
"myResponseA": $1,
"myResponseB": $2
}
]]>
</format>
<args>
<arg expression="get-property('myResponseA')"/>
<arg expression="get-property('myResponseB')"/>
</args>
</payloadFactory>
<property name="HTTP_SC" scope="axis2" type="STRING" value="200"/>
<send/>
The problem is, the OUT sequence is called multiple times, one for each sequence in Clone mediator.
I tried to use the Aggregate mediator with no luck, 'coz my apis is restful and i don't know how to use the aggregate expression. I dont even need it, because i put the responses in different properties and read it in my payloadFactory.
How to execute my OUT sequence only one single time when all my sequences return in clone mediator? or there is another mediator i should use?
Obs.: I have to call those apis in parallel, because each one will take some time, and i will call 5~10 each time.
Can you try this as a startup :-D
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="PoCCloneAggregate"
transports="http"
startOnLoad="true"
statistics="enable"
trace="enable">
<description/>
<target>
<inSequence>
<property name="enclosing_element" scope="default">
<result xmlns=""/>
</property>
<clone continueParent="false" sequential="true">
<target>
<sequence>
<log level="custom">
<property name="CLON" value="clon 1"/>
</log>
<payloadFactory media-type="json">
<format>
{"data":
{"temperatura":"10",
"id":"1"}}
</format>
<args>
</args>
</payloadFactory>
<loopback/>
</sequence>
</target>
<target>
<sequence>
<log level="custom">
<property name="CLON" value="clon 2"/>
</log>
<payloadFactory media-type="json">
<format>
{"data":
{"temperatura":"20",
"id":"2"}}
</format>
<args>
</args>
</payloadFactory>
<loopback/>
</sequence>
</target>
<target>
<sequence>
<log level="custom">
<property name="CLON" value="clon 3"/>
</log>
<payloadFactory media-type="json">
<format>
{"data":
{"temperatura":"30",
"id":"3"}}
</format>
<args>
</args>
</payloadFactory>
<loopback/>
</sequence>
</target>
</clone>
</inSequence>
<outSequence>
<log level="full"/>
<aggregate>
<completeCondition>
<messageCount min="-1" max="-1"/>
</completeCondition>
<onComplete expression="$body/jsonObject" xmlns:s12="http://www.w3.org/2003/05/soap-envelope"
xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/" enclosingElementProperty="enclosing_element">
<log level="custom" separator=",">
<property name="MessageFlow" value="======================= Respuestas Agregadas. ==============="/>
</log>
<log level="full" separator=","/>
<send/>
</onComplete>
</aggregate>
</outSequence>
<faultSequence/>
</target>
</proxy>
You have to use aggragate mediator, the goal is to route each response to a single sequence containing this aggregate.
For example, if you use send mediator inside mySequenceA and mySequenceB, define the "receive" attribute to route the response in a dedicated sequence with <send receive="myResponseSequence"> (the same "myResponseSequence" must be used in mySequenceA and B).
If you use call mediator, then call a dedicated sequence with <sequence key="myResponseSequence"> (the same "myResponseSequence" must be used in mySequenceA and B)
inside myResponseSequence, use aggregate mediator :
the completeCondition can be let to default, the ESB will wait to receive the same number of response than the number of targets in your clone mediator. It gives you someting like :
<completeCondition>
<messageCount min="-1" max="-1"/>
</completeCondition>
the onComplete contains the mediation sequence that will be executed as soon as all the responses will be there : this sequence must contain the send mediator that will send a single response to the caller. The "expression" attribute on this "onComplete" node will contain an xpath that tell which node from the response must arrive inside the onComplete sequence.
inside the onComplete sequence, you can use payloadMediator to compose your single response
<onComplete xmlns:ns="http://org.apache.synapse/xsd" expression="//values">
<payloadFactory media-type="xml">
<format>
<myCustomResponse>
<result>$1</result>
</myCustomResponse>
</format>
<args>
<arg evaluator="xml" expression="//values"/>
</args>
</payloadFactory>
<send/>
</onComplete>
The fact that your api is restful should not be a problem with aggregate mediator. Perhaps the format is json and not xml : use json-eval if you want for the xpath or media-type=json" inside payloadFactory

How to customize error XML response from api manager to a simple JSON message?

When invoking a published API with invalid access token, a XML response was got.
900901
Invalid Credentials
Access failure for API: /sit/zxq/oapi/ut/1.0, version: 1.0 with key: b645348f2ca7fea5a9cf498e4085a471. Make sure your have given the correct access token
How could we customize such response to following JSON format?
{
"req_id": "REQ_ENT_1356985018299_9678",
"err_resp": {
"code": "28001",
"msg": "Invalid access token"
}
}
Thanks and looking forward to your expertise.
We've recently done something similar with our API Manager implementation. You can find the fault sequences in /repository/deployment/server/synapise-configs/default/sequences, match on the error code, and provide your own JSON content. You can also use a switch mediator (the fault sequences are just mediation sequences) to return the correct content type for various Accept header values. Just replace the payload written in the fault.xml file with the equivalent JSON content (or as suggested, write a switch to allow the support of both content types).
You need to target the error codes from https://docs.wso2.com/display/AM260/Error+Handling and update it to your custom JSON messages. For auth token related errors try modify _auth_failure_handler_ as below:
<sequence name="_auth_failure_handler_" xmlns="http://ws.apache.org/ns/synapse">
<property name="error_message_type" value="application/json"/>
<filter source="get-property('ERROR_CODE')" regex="405">
<then>
<sequence key="converter"/>
<drop/>
</then>
<else>
</else>
</filter>
<filter source="get-property('ERROR_CODE')" regex="900901">
<then>
<sequence key="invalidCredential"/>
<drop/>
</then>
<else>
</else>
</filter>
<filter source="get-property('ERROR_CODE')" regex="900902">
<then>
<sequence key="missingCredential"/>
<drop/>
</then>
<else>
</else>
</filter>
<sequence key="_cors_request_handler_"/>
For your case Invalid Credential has a 900901 code , so it will match and need to define invalidCredential.xml as below :
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="invalidCredential">
<payloadFactory media-type="json">
<format>{ "req_id": "REQ_ENT_1356985018299_9678", "err_resp": { "code": "28001", "msg": "Invalid access token" } </format>
<!--Add your custom message and format here. This will be your output-->
</payloadFactory>
<property name="RESPONSE" value="true"/>
<header name="To" action="remove"/>
<property name="HTTP_SC" value="401" scope="axis2"/>
<property name="messageType" value="application/json" scope="axis2"/>
<send/>
</sequence>

why the response is strange in wso2

I use postman to test
http://192.168.1.208:8090/jobsappName=sparkJoin001&classPath=com.mymoon.sql.SparkJoin
It's ok! It returns the message:
{
"status": "STARTED",
"result": {
"jobId": "3a47f931-f040-4e4a-a688-331f1918ae82",
"context": "6a171d9d-com.mymoon.sql.SparkJoin"
}
}
it's http status is 202!
I config in the wso2 esb and return some messages, but the browse shows the mixed message! It's stange!
The config is :
<api xmlns="http://ws.apache.org/ns/synapse" name="d" context="/dd">
<resource methods="GET" uri-template="/submit">
<inSequence>
<log level="full"/>
<payloadFactory media-type="text">
<format>{"uuid":"201456541","table": "aa/aa_table","condition":"names|91194185"}</format>
<args/>
</payloadFactory>
<send>
<endpoint>
<http method="POST" uri-template="http://192.168.1.208:8090/jobs?appName=CU&classPath=com.mymoon.ses.SparkCount"/>
</endpoint>
</send>
</inSequence>
<outSequence>
<log level="full">
<property name="asdfsadf" expression="json-eval($.)"/>
</log>
<payloadFactory media-type="text">
<format>{"jobId":"$1", "table":"$2"}</format>
<args>
<arg evaluator="json" expression="$.result.jobId"/>
<arg value="test"/>
</args>
</payloadFactory>
<send/>
</outSequence>
</resource>
</api>
So I test http://192.168.1.101:8280/dd/submit . The browser shows such message.
{
"status": "STARTED",
"result": {
"jobId": "548e9590-e442-439f-9234-223bf5bf669e",
"context": "dd803c98-com.mymoon.ses.SparkCount"
}
}{"jobId":"548e9590-e442-439f-9234-223bf5bf669e", "table":"test"}
I hope message is this:
{"jobId":"548e9590-e442-439f-9234-223bf5bf669e", "table":"test"}
So I'm confused! Help me!Thanks!
i have tested using ESB 4.8.0. i have modified your API code as follows. I tested with mock service and its working. only change i made is change media-type json from text
<api xmlns="http://ws.apache.org/ns/synapse" name="d" context="/dd">
<resource methods="GET" uri-template="/submit">
<inSequence>
<log level="full"></log>
<payloadFactory media-type="json">
<format>{"uuid":"201456541", "table": "aa/aa_table", "condition":"names|91194185" }</format>
<args></args>
</payloadFactory>
<send>
<endpoint>
<http method="post" uri-template="http://demo2965385.mockable.io/test"></http>
</endpoint>
</send>
</inSequence>
<outSequence>
<log level="full">
<property name="asdfsadf" expression="json-eval($.)"></property>
</log>
<payloadFactory media-type="json">
<format>{"jobId":"$1", "table":"$2"}</format>
<args>
<arg evaluator="json" expression="$.result.jobId"></arg>
<arg value="test"></arg>
</args>
</payloadFactory>
<send></send>
</outSequence>
</resource>
</api>
response look as follows
{
"jobId": "3a47f931-f040-4e4a-a688-331f1918ae82",
"table": "test"
}

WSO2 mediator return error message to user

I'm currently trying to write a java mediator in WSO2 API manager to perform some processing before sending the message to the proxy.
The normal use cases work fine, but I'm having some trouble with exceptions.
I would like to be able to send a message back to the user from the mediator, with a message and a HTTP status code, but I can't see a way to do it.
import org.apache.synapse.mediators.transform.PayloadFactoryMediator;
public class MessageMediator extends PayloadFactoryMediator
{
#Override
public boolean mediate(org.apache.synapse.MessageContext synapseMessageContext)
{
boolean success = true;
try{
.... some processing
}
catch(Exception e)
{
success = false;
handleException(e.getMessage(), e, synapseMessageContext);
//write message back to user
}
return success;
}
}
This is my proxy:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="AMQPProxy"
transports="https http"
startOnLoad="true"
trace="enable">
<description/>
<target>
<endpoint>
<default />
</endpoint>
<inSequence>
<sequence key="MessageMediator"/>
</inSequence>
<outSequence>
<send/>
</outSequence>
</target>
</proxy>
What is the correct procedure to return an error to the user?
Thanks
If you are returning the error from the insequence itself without going out of wso2 esb calling another service you can do it as :
<payloadFactory media-type="json">
<format>{"Error":{"errorType":"BusinessError","details":"some details"}}</format>
<args/>
</payloadFactory>
<header name="To" scope="default" action="remove"/>
<property name="RESPONSE" value="true" scope="default" type="STRING"/>
<property name="HTTP_SC" value="400" scope="axis2" type="STRING"/>
<property name="messageType" expression="$trp:Accept" scope="axis2" type="STRING"/>
<send/>
You can do similarly with media-type as xml see payload factory mediator
If you are going to return error from outsequence you can use makefault see here Fault mediator you can try using fault mediator in insequence as well i haven't tried yet but when sending in insequence you need to use
<header name="To" scope="default" action="remove"/>
in my case, if the username is empty(you can use any http code(in my sample 406)):
<filter source="json-eval($.loginStatic.request.username)" regex="^null|$">
<then>
<property name="HTTP_SC" value="406" scope="axis2"/>
<property name="messageType" value="application/json" scope="axis2" type="STRING"/>
<payloadFactory media-type="json">
<format>{ "status": "ERROR!"}</format>
<args/>
</payloadFactory>
<send/>
</then>
</filter>