mule mapping-exception-strategy only falls through to first 401 branch - mule

asking this for some mulesoft expertise.
the following exception mapping strategy is supposed to branch on hhtp.status 401, 403, 429 but keeps on falling into the 401 branch for status codes 401 and 403 (at least, and determined by both debugging and log written to console):
<apikit:mapping-exception-strategy doc:name="waysact-adaptor-main-exception-strategy">
<apikit:mapping statusCode="401">
<apikit:exception value="org.mule.module.http.internal.request.ResponseValidatorException"/>
<logger message="psc>>> logging 401 = #[payload]" level="INFO" doc:name="log-http-401"/>
</apikit:mapping>
<apikit:mapping statusCode="403">
<apikit:exception value="org.mule.module.http.internal.request.ResponseValidatorException"/>
<logger message="psc>>> logging 403 = #[payload]" level="INFO" doc:name="log-http-403"/>
</apikit:mapping>
<apikit:mapping statusCode="429">
<apikit:exception value="org.mule.module.http.internal.request.ResponseValidatorException"/>
<logger message="psc>>> logging 429 = #[payload]" level="INFO" doc:name="log-http-429"/>
</apikit:mapping>
<apikit:mapping statusCode="400">
<apikit:exception value="org.mule.module.http.internal.request.ResponseValidatorException"/>
<logger message="psc>>> logging anything = #[payload]" level="INFO" doc:name="logging-anything"/>
</apikit:mapping>
</apikit:mapping-exception-strategy>
is this because it is branching only on exception type org.mule.module.http.internal.request.ResponseValidatorException? i thought it was meant to branch on the status code?
there is another strategy, choice-exception-strategy, that should branch on different exception object types.

Branching of exception based on http.status can be defined with choice exception strategy as below example,
<choice-exception-strategy doc:name="Choice Exception Strategy">
<catch-exception-strategy when="#[message.inboundProperties.'http.status'=='404']" doc:name="Catch Exception Strategy" >
<logger message="Exceptions message is ... #[exception.message]" level="ERROR" doc:name="exceptionLogger"/>
<set-variable variableName="exceptionMessage" value="#[exception.message]" doc:name="Set exceptionMessage"/>
<set-payload value="{ errors: { errorCode: #[message.inboundProperties.'http.status'], errorMessage: #[flowVars.exceptionMessage] } }" doc:name="Set Exception Payload"/>
</catch-exception-strategy>
<catch-exception-strategy doc:name="Catch Exception Strategy" >
<logger message="Exception message is ... #[exception.message]" level="ERROR" category="com.project.stacktrace" doc:name="exceptionLogger"/>
<set-variable variableName="exceptionMessage" value="#[exception.message]" doc:name="Set exceptionMessage"/>
<set-payload value="{ errors: { errorCode: #[message.inboundProperties.'http.status'], errorMessage: #[flowVars.exceptionMessage] } }" doc:name="Set Exception Payload"/>
</catch-exception-strategy>
</choice-exception-strategy>

APIkit matches the exception based on the exception value defined and not by the statusCode defined. Use choice exception strategy and define multiple catch exception strategy in it. Make sure each catch exception strategy matches a unique exception to make the way for proper http.status code and desired exception payload.
For example, if you want to have 400 to be thrown, make sure a catch exception strategy matches BadrequestException. If the status codes are coming out of the HTTP requester, match the ResponseValidatorException and set the incoming http.status and exception payload

Related

Mulesoft - How to find Http error payload in exception object?

How to find Http error payload in exception object ?
System 1 -> Call's Mule server . Mule server -> Docusign / some one else.
Docusign / some one returns 400 error with json payload (includes errorCode etc)
I need to return the exact details back to System 1.
how will i do this?
1) I did try to add all codes in success codes 200..599, then even error is having 200 ok . This will cause more problem, because I have to add lot of choice routing as some flows are having more data conversion.
2) Ideal soln -> Raise exception as usual. This has to be caught in choice exception. Now I have to send the same status_code and the json response back to the caller.
Issue -? how can i find the payload returned by HTTP in exception object. Where is stored in exception object.
Here is the sample- one way of handling this kind of scenario , use validation Component to throw exception and capture in your mainflow either by exceptionHandling or by APIKIT ExceptionHandling
<flow name="routeexceptionFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/test" doc:name="HTTP"/>
<logger level="INFO" doc:name="Logger"/>
<http:request config-ref="HTTP_Request_Configuration" path="/in" method="POST" doc:name="HTTP">
<http:success-status-code-validator values="200..599"/>
</http:request>
<validation:is-false config-ref="Validation_Configuration" message="#[payload]" exceptionClass="nz.co.exception.BadRequestException" expression="#[message.inboundProperties['http.status'] ==400]" doc:name="Validate Bad Request"/>
<validation:is-false config-ref="Validation_Configuration" message="#[payload]" expression="#[message.inboundProperties['http.status'] !=200]" doc:name="Capture all other Exceptions"/>
<choice-exception-strategy doc:name="Choice Exception Strategy">
<catch-exception-strategy when="#[exception.causeMatches('nz.co.exception.BadRequestException')]" doc:name="Catch Exception Strategy">
<set-payload value="#[exception.message]" doc:name="Set Payload"/>
<logger level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<logger message="****log all other exception****" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</choice-exception-strategy>
</flow>
Add this class in your java folder
package nz.co.exception;
public class BadRequestException extends Exception {
private static final long serialVersionUID = 8546839078847602529L;
public BadRequestException() {
super();
}
public BadRequestException(String message) {
super(message);
}
public BadRequestException(Throwable t) {
super(t);
}
public BadRequestException(String message, Throwable t) {
super(message, t);
}
}
In your project if you are using APIKIT Router , then instead of using exceptionHandling as above, add directly nz.co.exception.BadRequestException in 400 ReturnCode apikitExceptionHandling.

Mule 3 to Mule 4 error handling queries for error types and http status

I am migrating an error handling file from Mule 3 to Mule 4 using Anypoint Studio 7.
My queries are:
How would I do I now do this check as I cannot see the same information in the exception message? #[exception.causedBy(org.mule.module.http.internal.request.ResponseValidatorException)]"
Where do I find the http.status property now? I can see it as a variable when it is 200 but when the error is thrown it seems to disappear and cannot locate it in the message
Where can I find a list of error handling types?
The error handling types I'm particularly interested in are below but no idea if that is the correct value for the error type:
HTTP:BAD_REQUEST
HTTP:UNAUTHORIZED
HTTP:FORBIDDEN
HTTP:RESOURCE_NOT_FOUND
HTTP:METHOD_NOT_ALLOWED
HTTP:NOT_ACCEPTABLE
HTTP:CONFLICT
HTTP:UNSUPPORTED_MEDIA_TYPE
HTTP:INTERNAL_SERVER_ERROR
HTTP:BAD_GATEWAY
Snippet of the Mule 3 code I am migrating is below and I think it was based on a template:
<choice-exception-strategy name="global-exception-strategy">
<catch-exception-strategy when="#[exception.causedBy(org.mule.module.http.internal.request.ResponseValidatorException)]" doc:name="Caused By (org.mule.module.http.internal.request.ResponseValidatorException)">
<choice doc:name="Choice">
<when expression="#[message.inboundProperties['http.status'] == 401]">
<set-variable variableName="errorMessage" value="Upstream service did not authorize the request." doc:name="Set Error Message"/>
<flow-ref name="global-bad-gateway-response-sub-flow" doc:name="Bad Gateway Response"/>
</when>
<otherwise>
<set-variable variableName="errorMessage" value="Upstream service internal error." doc:name="Set Error Message"/>
<flow-ref name="global-bad-gateway-response-sub-flow" doc:name="Bad Gateway Response"/>
</otherwise>
</choice>
</catch-exception-strategy>
</choice-exception-strategy>
<sub-flow name="global-bad-gateway-response-sub-flow">
<set-property propertyName="http.status" value="401" doc:name="Set Status"/>
<set-payload value="UNAUTHORIZED" doc:name="Set Error Code" mimeType="application/java"/>
<flow-ref name="global-prepare-error-response-sub-flow" doc:name="Prepare Error Response"/>
</sub-flow>
Thanks
Use these kind of check
#[contains(error.description,'internal server error (500).')]
in Mule 4 http status code for error response located here
#[error.errorMessage.attributes['statusCode']]

Mule Exception strategy definition: Invalid content was found starting with element 'choice-exception-strategy'

I'm developing a mule work-flow to insert a record into the database, trying to catch the exception in case if the record is already present and send the HTTP status (409-Conflict) and the back to the client.
<when expression="#[message.inboundProperties['http.method'] == 'POST']">
<json:json-to-object-transformer returnClass="java.lang.Object" doc:name="JSON to Object" />
<set-variable variableName="id" value="#[message.payload.id]" doc:name="Save brandId"/>
<json:object-to-json-transformer doc:name="Object to JSON"/>
<db:insert config-ref="Postgres" doc:name="Configstore">
<db:parameterized-query><![CDATA[INSERT INTO messages("id", "data") VALUES ( #[flowVars['id']], CAST(#[message.payload] as json))]]> </db:parameterized-query>
</db:insert>
<logger message="REST Response = #[message.payload]" level="INFO" doc:name="LOG Rest Response"></logger>
<choice-exception-strategy name="Global_Choice_Exception_Strategy" doc:name="Global Choice Exception Strategy">
<catch-exception-strategy doc:name="Catch_Exception_Strategy" when="#[exception.causedBy(org.postgresql.util.PSQLException)]">
<set-payload value="The request cannot be processed, the error is #[exception.getExceptionPayload()]"/>
<set-property propertyName="http.status" value="404"/>
<http:outbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" method="POST" doc:name="HTTP"/>
</catch-exception-strategy>
</choice-exception-strategy>
</when>
The start-up is repeatedly failing and the following error reported in the logs.
cvc-complex-type.2.4.a: Invalid content was found starting with element 'choice-exception-strategy'. One of '{"http://www.mulesoft.org/schema/mule/core":abstract-message-processor, "http://www.mulesoft.org/schema/mule/core":abstract-outbound-endpoint, "http://www.mulesoft.org/schema/mule/core":abstract-mixed-content-message-processor}' is expected.
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source) ~[?:?]
This error alternatively reported for both choice-exception-strategy and catch-exception-strategy. Not sure what's invalid here or need to define a custom message-processor or outbound-endpoint. I'm using mule EE-3.8.0
The problem is that you are using an exception strategy within a choice element. The exception strategy must be defined for your whole flow, not single elements (some do allow them though but are rare cases). You can find more on this here and an example here.
HTH

Exception Logging in Batch in Mulesoft

I have a case, where I have to log the exception error in an object in Salesforce, where I have to also take the payload (the record) for which error is there. The error here will be the record level error and I am using a batch process for this. In the screenshot there is how we are processing the exception.
Following is the xml
<batch:step name="HandleFailedRecords_AccountSF-360" accept-policy="ONLY_FAILURES">
<set-payload value="#[getStepExceptions()]" doc:name="Set Payload"/>
<foreach doc:name="For Each" collection="#[payload.values()]">
<set-variable variableName="Record_level_error" value="#[payload]" doc:name="Record_level_error"/>
<dw:transform-message doc:name="Transform Message" metadata:id="9c2e408a-f530-4ffd-a205-a787c8bc94b2">
<dw:set-payload><![CDATA[%dw 1.0
%output application/java
---
payload map
{
SF_Object_Type__c: "Account"
}]]></dw:set-payload>
</dw:transform-message>
<sfdc:create config-ref="Salesforce__Basic_Authentication" type="Exception__c" doc:name="Salesforce">
<sfdc:objects ref="#[payload]"/>
</sfdc:create>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
<!-- <flow-ref name="HandleRecordFailure" doc:name="HandleRecordFailure"/> -->
</foreach>
</batch:step>
</batch:process-records>
Here I am able to get what exception I am getting, but what else I need is for which value it is getting errored out.
Bast way to handle properly exception handling in batch processing is to do a flow-ref to a normal flow with his proper exception handling, there you will be able to handle your exception in a standard mule way and do what you need in the exception catch flow.
Hope this helps
Regards

Scatter gather routing error. Message payload is of type: String

I'm new to Mule and while working on a fairly simple Hello World example on Anypoint Studio to test out the Scatter/Gather flow control element, I'm getting the following error, without much else in the way of information:
ERROR 2014-12-19 22:00:30,172 [[unifinesb].connector.http.mule.default.receiver.02] org.mule.exception.DefaultMessagingExceptionStrategy:
********************************************************************************
Message : Exception was found for route(s): 0. Message payload is of type: String
Type : org.mule.routing.CompositeRoutingException
Code : MULE_ERROR--2
JavaDoc : http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/routing/CompositeRoutingException.html
Payload : /Waldo
********************************************************************************
Exception stack is:
1. Exception was found for route(s): 0. Message payload is of type: String (org.mule.routing.CompositeRoutingException)
org.mule.routing.CollectAllAggregationStrategy:51 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/routing/CompositeRoutingException.html)
********************************************************************************
Root Exception stack trace:
org.mule.routing.CompositeRoutingException: Exception was found for route(s): 0. Message payload is of type: String
at org.mule.routing.CollectAllAggregationStrategy.aggregateWithFailedRoutes(CollectAllAggregationStrategy.java:51)
at org.mule.routing.CollectAllAggregationStrategy.aggregate(CollectAllAggregationStrategy.java:38)
at org.mule.routing.ScatterGatherRouter.processResponses(ScatterGatherRouter.java:207)
at org.mule.routing.ScatterGatherRouter.process(ScatterGatherRouter.java:135)
at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
at org.mule.execution.MessageProcessorNotificationExecutionInterceptor.execute(MessageProcessorNotificationExecutionInterceptor.java:58)
at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
at org.mule.execution.ExceptionToMessagingExceptionExecutionInterceptor.execute(ExceptionToMessagingExceptionExecutionInterceptor.java:24)
at org.mule.execution.MessageProcessorExecutionTemplate.execute(MessageProcessorExecutionTemplate.java:44)
at ...
Judging from the top description of the error, I understand the problem to be that Scatter gather does not receive String payloads, even though the current documentation for the component mentions nothing of the sort. Is this correct?
The flow I'm running is fairly simple, receiving a String from an inbound http and trying to route it to a REST service that will use the String to print something (returning text/plain) and to a DB to store the String in a table. Relevant code follows:
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8084" doc:name="HTTP"/>
<expression-filter expression="#[payload != '/favicon.ico']" doc:name="Filter browser icon padding"/>
<logger message="current payload is #[payload]" level="INFO" doc:name="Startup log - to stdout"/>
<scatter-gather doc:name="Scatter-Gather">
<processor-chain>
<logger message="#['Rest branch msg input :' + payload]" level="DEBUG" doc:name="File Logger"/>
<http:outbound-endpoint exchange-pattern="request-response" method="POST" address="http://localhost:8080/application/rest/mensaje?givenName=#[payload]" doc:name="REST Service"/>
<logger message="#['Rest msg output :' + payload]" level="DEBUG" doc:name="File Logger"/>
</processor-chain>
<processor-chain>
<logger message="#['Database msg input :' + payload]" level="DEBUG" doc:name="File Logger"/>
<db:insert config-ref="MySQL_VestaLocal" doc:name="Application Postgress">
<db:parameterized-query><![CDATA[insert into http_user_info (first_name) values ('#[payload]');]]></db:parameterized-query>
</db:insert>
<logger message="#['Database msg output :' + payload]" level="DEBUG" doc:name="File Logger"/>
</processor-chain>
</scatter-gather>
<set-payload value="#['REST DB Success!']" doc:name="Set Payload"/>
Trawling through the net I found this old Mule JIRA issue with an exception similar to what I'm getting, but trying out the suggested solution (workaround?) didn't do anything for me: https://www.mulesoft.org/jira/browse/MULE-7594
Something wrong is happening in your route 0.
You are getting a composite routing exception as per documentation:
The CompositeRoutingException is new to the 3.5.0 Runtime. It extends
the Mule MessagingException to aggregate exceptions from different
routes in the context of a single message router. Exceptions are
correlated to each route through a sequential ID.
This exception exposes two methods which allow you to obtain the IDs
of failed routes and the exceptions returned by each route.
The getExceptions method returns a map where the key is an integer
that identifies the index of the failed route, and the value is the
exception itself. The getExceptionForRouteIndex(int) method returns
the exception of the requested route ID.
As you don't have an execption strategy, the toString is call to that exception and that only prints the route failing (that has nothing to do with the fact that the payload is String)
Please use the following exeption strategy to find out exactly what's wrong:
<catch-exception-strategy doc:name="Catch Exception Strategy">
<logger level="ERROR" message="#[exception.exceptions]"/>
</catch-exception-strategy>