Sending PDF over HTTP Request in Mule 4 - mule

I have in my flow an HTTP request (say, DOC Service) where I get a PDF from a service, and I have to send the PDF to an OCR application through another HTTP Request (say, OCR Service). I am receiving the PDF from DOC Service as application/pdf type, and the OCR Service is set to receive multipart/form-data type.
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:ftp="http://www.mulesoft.org/schema/mule/ftp" xmlns:file="http://www.mulesoft.org/schema/mule/file"
xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">
<flow name="on-mq-messageFlow" doc:id="eca15aeb-da46-491a-97e1-f73aa5fcd45b" >
<set-payload value='#[%dw 2.0
output application/json
---
read(payload,"application/json")]' doc:name="Set Payload" doc:id="929f7b70-ae47-4fe3-abd2-e89ae092899e" />
<set-variable value="#[payload]" doc:name="Set MQ Payload" doc:id="9716ed4b-4d16-4b9e-8ac8-1dab5646fe0f" variableName="mqPayload"/>
<http:request method="POST" doc:name="Doc Request" doc:id="0e92add3-d576-444d-8070-9d09e6e3c5c5" config-ref="DOC_configuration" path="${doc.request.path}" outputMimeType='multipart/form-data; boundary=----aA1bB2cC3dD4'>
<http:headers ><![CDATA[#[output application/java
---
{
"client-id" : "12345",
"client-secret" : "12345"
}]]]></http:headers>
<http:uri-params ><![CDATA[#[output application/java
---
{
"doc_id" : payload.data.ID
}]]]></http:uri-params>
</http:request>
<http:request method="POST" doc:name="Send Doc to OCR" doc:id="76f60ddb-f570-42be-b85e-ccb2d2ae3703" config-ref="OCR_Request_configuration" path="${ocr.request.path}" outputMimeType="multipart/form-data; boundary=----aA1bB2cC3dD4">
<http:body ><![CDATA[#[%dw 2.0
output multipart/form-data
---
{
parts: {
file: {
headers: {
"Content-Type": payload.^mimeType
},
content: payload
},
id: {
headers: {
"Content-Type": "text/plain"
},
content: vars.mqPayload.data.ID
}
}
}]]]></http:body>
<http:headers ><![CDATA[#[output application/java
---
{
"client-id" : "12345",
"Accept" : "*/*",
"client-secret" : "12345",
"Content-Type" : "multipart/form-data; boundary=----aA1bB2cC3dD4"
}]]]></http:headers>
</http:request>
<ee:transform doc:name="Final Response" doc:id="cf68dbc1-cee3-4809-9511-a0794be2b5f7">
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
"status": "Success",
message: "Completed"
}
]]></ee:set-payload>
</ee:message>
</ee:transform>
</flow>
</mule>
I have to add another text field along with the PDF file before sending the payload to OCR Service. For that, I have defined payload as multipart/form-data by selecting the elements of parts of form-data and modifying it like given in the answer here, but getting below error. I have also set MimeType for both DOC Service and OCR Service as multipart/form-data.
ERROR 2020-12-05 21:57:57,159 [[MuleRuntime].cpuLight.02: [doc-process-api].on-mq-messageFlow.CPU_LITE #6ec62e93] [event: 0e82ca00-3717-11eb-ab69-005056ac6a26] org.mule.runtime.core.internal.exception.OnErrorPropagateHandler:
********************************************************************************
Message : "javax.mail.internet.ParseException - Missing start boundary, while reading `payload` as MultiPart.
Trace:
at main (Unknown), while writing MultiPart.
Trace:
at main (Unknown)" evaluating expression: "%dw 2.0
output multipart/form-data
---
{
parts: {
file: {
headers: {
"Content-Type": payload.^mimeType
},
content: payload
},
external_id: {
headers: {
"Content-Type": "text/plain"
},
content: vars.mqPayload.data.ID
}
}
}".
Element : on-mq-messageFlow/processors/4 # doc-process-api:on-mq-message.xml:46 (Send Doc to OCR)
Element XML : <http:request method="POST" doc:name="Send Doc to OCR" doc:id="76f60ddb-f570-42be-b85e-ccb2d2ae3703" config-ref="OCR_Request_configuration" path="${ocr.request.path}" outputMimeType="multipart/form-data; boundary=----aA1bB2cC3dD4">
<http:body>#[%dw 2.0
output multipart/form-data
---
{
parts: {
file: {
headers: {
"Content-Type": payload.^mimeType
},
content: payload
},
external_id: {
headers: {
"Content-Type": "text/plain"
},
content: vars.mqPayload.data.ID
}
}
}]</http:body>
<http:headers>#[output application/java
---
{
"client-id" : "12345",
"Accept" : "*/*",
"client-secret" : "12345",
"Content-Type" : "multipart/form-data; boundary=----aA1bB2cC3dD4"
}]</http:headers>
</http:request>
Error type : MULE:EXPRESSION
Payload Type : org.mule.runtime.core.internal.streaming.bytes.ManagedCursorStreamProvider
--------------------------------------------------------------------------------
Root Exception stack trace:
org.mule.runtime.api.el.ExpressionExecutionException: javax.mail.internet.ParseException - Missing start boundary, while reading `payload` as MultiPart.
Trace:
at main (Unknown), while writing MultiPart.
Trace:
at main (Unknown)
at org.mule.weave.v2.el.WeaveExpressionLanguageSession.doEvaluate(WeaveExpressionLanguageSession.scala:130)
at org.mule.weave.v2.el.WeaveExpressionLanguageSession.evaluate(WeaveExpressionLanguageSession.scala:77)
at org.mule.weave.v2.el.WeaveExpressionLanguageSession.evaluate(WeaveExpressionLanguageSession.scala:103)
at org.mule.runtime.core.internal.el.dataweave.DataWeaveExpressionLanguageAdaptor$1.evaluate(DataWeaveExpressionLanguageAdaptor.java:252)
at org.mule.runtime.core.internal.el.DefaultExpressionManagerSession.evaluate(DefaultExpressionManagerSession.java:38)
at org.mule.runtime.core.privileged.util.attribute.ExpressionAttributeEvaluatorDelegate.resolveExpressionWithSession(ExpressionAttributeEvaluatorDelegate.java:70)
at org.mule.runtime.core.privileged.util.attribute.ExpressionAttributeEvaluatorDelegate.resolve(ExpressionAttributeEvaluatorDelegate.java:56)
at org.mule.runtime.core.privileged.util.AttributeEvaluator.resolveTypedValue(AttributeEvaluator.java:104)
at org.mule.runtime.module.extension.internal.runtime.resolver.ExpressionValueResolver.resolveTypedValue(ExpressionValueResolver.java:122)
at org.mule.runtime.module.extension.internal.runtime.resolver.ExpressionTypedValueValueResolver.resolve(ExpressionTypedValueValueResolver.java:46)
at org.mule.runtime.module.extension.internal.runtime.resolver.ExpressionTypedValueValueResolver.resolve(ExpressionTypedValueValueResolver.java:29)
at org.mule.runtime.module.extension.internal.runtime.resolver.ResolverUtils.resolveRecursively(ResolverUtils.java:90)
at org.mule.runtime.module.extension.internal.runtime.resolver.ResolverSet.resolve(ResolverSet.java:109)
at org.mule.runtime.module.extension.internal.runtime.operation.ComponentMessageProcessor.getResolutionResult(ComponentMessageProcessor.java:586)
at org.mule.runtime.module.extension.internal.runtime.operation.ComponentMessageProcessor.lambda$apply$6(ComponentMessageProcessor.java:194)
at org.mule.runtime.core.api.util.func.CheckedFunction.apply(CheckedFunction.java:19)
at org.mule.runtime.core.api.rx.Exceptions.lambda$checkedFunction$2(Exceptions.java:84)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:381)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.tryEmit(FluxFlatMap.java:532)
at reactor.core.publisher.FluxFlatMap$FlatMapInner.onNext(FluxFlatMap.java:974)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2071)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:162)
at reactor.core.publisher.FluxFlatMap$FlatMapInner.onSubscribe(FluxFlatMap.java:964)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90)
at reactor.core.publisher.MonoCurrentContext.subscribe(MonoCurrentContext.java:35)
at reactor.core.publisher.MonoMapFuseable.subscribe(MonoMapFuseable.java:59)
at reactor.core.publisher.Mono.subscribe(Mono.java:3858)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:420)
at org.mule.runtime.core.privileged.processor.chain.AbstractMessageProcessorChain$1.onNext(AbstractMessageProcessorChain.java:292)
at org.mule.runtime.core.privileged.processor.chain.AbstractMessageProcessorChain$1.onNext(AbstractMessageProcessorChain.java:285)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:204)
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:345)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:204)
at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.tryOnNext(FluxContextStart.java:111)
at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.tryOnNext(FluxContextStart.java:109)
at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.tryOnNext(FluxMapFuseable.java:303)
at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.tryOnNext(FluxContextStart.java:109)
at reactor.core.publisher.FluxPublishOn$PublishOnConditionalSubscriber.runAsync(FluxPublishOn.java:866)
at reactor.core.publisher.FluxPublishOn$PublishOnConditionalSubscriber.run(FluxPublishOn.java:939)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84)
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at org.mule.service.scheduler.internal.AbstractRunnableFutureDecorator.doRun(AbstractRunnableFutureDecorator.java:111)
at org.mule.service.scheduler.internal.RunnableFutureDecorator.run(RunnableFutureDecorator.java:54)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
To fix that I tried adding boundary in headers as Content-Type like below, and still getting the same error.
"Content-Type: "multipart/form-data; boundary=----aA1bB2cC3dD4"
Here I don't need to parse anything, just handover the PDF from one service to another service, but by adding an extra field. How can I achieve this? Any help is appreciated.

The error is happening because you are miss typing the DOC service as multipart so DataWeave attempts to read the PDF as such. The mime type parameter affects the output of your operation, saying "this is the type I produce". But in the case of HTTP, that is automatically determined based on the "Content-Type" header, you do not need to specify the mime types beyond your DataWeave transformation for the ORC service.

I accepted #afelisatti's answer since that was the key point that helped me fix the error which I was getting; I am posting here how I was able to send the PDF over HTTP request in Mule 4.
Removed the output mime type I set for the OCR Service HTTP Request and set output mime type as application/pdf
Set the output payload from DOC Service (PDF) in Set Payload
Took out the payload which I have defined in OCR HTTP Request and put it in a transform message like below and made few changes. The changes are; added boundary along with output type, set a file name for the document in 'Content Disposition' as filename.
<ee:transform doc:name="Multipart Payload with ID" doc:id="cf68dbc1-cee3-4809-9511-a0794be2b5f7">
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
import * from dw::module::Multipart
output multipart/form-data; boundary=----aA1bB2cC3dD4"
---
{
parts: {
file: {
headers: {
"Content-Disposition": {
"name": "file",
"filename": vars.mqPayload.data.ID ++ "_Doc.pdf" as String
},
"Content-Type": "application/pdf"
},
content: payload
},
id: {
headers: {
"Content-Type": "text/plain"
},
content: vars.mqPayload.data.ID
}
}
}
]]></ee:set-payload>
</ee:message>
</ee:transform>
Added boundary and charset for muiltpart/form-data Content-Type header in OCR HTTP Request
"Content-Type":"multipart/form-data; charset=UTF-8; boundary=----aA1bB2cC3dD4"
The important thing is to set boundary and charset in HTTP Request headers and the same boundary is defined in the formdata payload, otherwise will result in bad request of boundary mismatch.

Related

Munit tests for the POst request end point

I am very new to Mulesoft and struggling to understand how to create the MUnit Tests for the simple flow which looks like below
<sub-flow name="salesforce-Opportunity-create-flow" doc:id="bd0263bf-7880-46d0-9c83-92376caa1bbb" >
<json-logger:logger doc:name="Begin Flow (Info)" doc:id="1f263a47-bb39-4748-b5b2-9e2f946cac58" config-ref="JSON_Logger_Config" message="Starting salesforce-Opportunity-create-flow" category="${jsonlogger.category}">
<json-logger:content><![CDATA[#[import modules::JSONLoggerModule output application/json ---
{
name: payload.name,
accountId: payload.accountId,
recordTypeId: payload.recordTypeId
}]]]></json-logger:content>
</json-logger:logger>
<ee:transform doc:name="Map Request Body" doc:id="ecee64bf-1b14-4261-bb29-c22d01f89726" >
<ee:message >
<ee:set-payload ><![CDATA[%dw 2.0
output application/java
---
[{
AccountId: payload.accountId,
RecordTypeId: payload.recordTypeId,
Name: payload.name,
StageName: payload.stageName,
CloseDate: payload.closeDate as Date,
LeadSource: payload.leadSource,
Pricebook2Id: payload.priceBook2ID,
Date_of_First_Contact__c: payload.dateOfFirstContact as Date,
Contact__c: payload.contact,
Service_Type__c: payload.serviceType,
SOW_Request_Date__c: payload.SowRequestDate as DateTime,
SOW_Generation_Stage__c: payload.SowGenerationStage
}]]]></ee:set-payload>
</ee:message>
</ee:transform>
<json-logger:logger doc:name="After Map Request Body (Info)" doc:id="6ef57816-a0ba-4f62-aa66-851467799ffc" config-ref="JSON_Logger_Config" message="After Map Request Body & Before Salesforce Create Operation in salesforce-Opportunity-create-flow" category="${jsonlogger.category}" tracePoint="AFTER_TRANSFORM">
<json-logger:content><![CDATA[#[import modules::JSONLoggerModule output application/json ---
{
Name: payload.Name,
AccountId: payload.AccountId,
RecordTypeId: payload.RecordTypeId
}]]]></json-logger:content>
</json-logger:logger>
<salesforce:create doc:name="Create" doc:id="e6b01da3-e86b-4d05-966d-cc410d5a2b7d" config-ref="Salesforce_Config" type="Opportunity"/>
<json-logger:logger doc:name="After Request to Salesforce (Info)" doc:id="5f397dec-ad2b-4672-a4a6-49b7cb55eccc" config-ref="JSON_Logger_Config" message="After Salesforce Create Operation in salesforce-Opportunity-create-flow" tracePoint="AFTER_REQUEST" category="${jsonlogger.category}">
<json-logger:content><![CDATA[#[import modules::JSONLoggerModule output application/json ---
{
success: payload.successful
}]]]></json-logger:content>
</json-logger:logger>
<ee:transform doc:name="Map Salesforce Response" doc:id="882badac-042c-420e-b58d-891345a51210" >
<ee:message >
<ee:set-payload ><![CDATA[%dw 2.0
output application/json
---
{
Id: payload.items[0].id
}]]></ee:set-payload>
</ee:message>
<ee:variables >
<ee:set-variable variableName="httpStatus" ><![CDATA[%dw 2.0
output application/json
---
payload.items[0].statusCode]]></ee:set-variable>
</ee:variables>
</ee:transform>
<json-logger:logger doc:name="End Flow (Info)" doc:id="a2e40bdb-e6e3-43e0-a0b2-eb85cb8f2d64" config-ref="JSON_Logger_Config" message="After Mapping Salesforce Response & End salesforce-Opportunity-create-flow" tracePoint="END" category="${jsonlogger.category}" >
<json-logger:content ><![CDATA[#[import modules::JSONLoggerModule output application/json ---
{
Id: payload.Id
}]]]></json-logger:content>
</json-logger:logger>
</sub-flow>
The above request is a POST endpoint that will create record in Salesforce. The articles I read was saying about Record Tests But I unable to do the record option for this application. The only other option I see is Create a blank test for the flow that just created the empty test
Most of the articles I referred was taking about GET. Any help/exaple of how I can mock the POST request will be great
You can use the example in the documentation to understand how to mock an HTTP Request with method POST:
<munit-tools:mock-when processor="http:request">
<munit-tools:with-attributes>
<munit-tools:with-attribute attributeName="method" whereValue="#['POST']"/>
</munit-tools:with-attributes>
<munit-tools:then-return>
<munit-tools:payload value="#['mockPayload']"/>
</munit-tools:then-return>
</munit-tools:mock-when>

Issue in uploading a file through http request using multipart/form-data in mule

Basically i have a curl command (which uploads a file to an API)which i want to execute this curl command through mule.I am reading the file from read connector. Then using multipart/form data to convert curl command.and then passing it to the HTTP requestor.
BUt while running the application. The API returns the error as 'Input file is missing'.
error message
* - - + APPLICATION + - - * - - + DOMAIN + - - * - - + STATUS + - - *
*******************************************************************************************************
* mule_mediaupload * default * DEPLOYED *
*******************************************************************************************************
INFO 2020-05-25 19:56:16,835 [[MuleRuntime].io.04: [mule_mediaupload].so-file-http-request-sendFlow.BLOCKING #9753a94] [event: b17cd1f0-9e93-11ea-95ae-681401007098] org.mule.runtime.core.internal.processor.LoggerMessageProcessor: Provider Name Date
Planetearth,2015-05-01
RockMusic,2017-09-01
INFO 2020-05-25 19:56:17,082 [[MuleRuntime].cpuIntensive.01: [mule_mediaupload].so-file-http-request-sendFlow.CPU_INTENSIVE #1fea2bb] [event: b17cd1f0-9e93-11ea-95ae-681401007098] org.mule.runtime.core.internal.processor.LoggerMessageProcessor: ------=_Part_2583_1939156918.1590416776933
Content-Type: text/plain
Content-Disposition: form-data; name="params"
{Type:Import}
------=_Part_2583_1939156918.1590416776933--
INFO 2020-05-25 19:56:20,781 [[MuleRuntime].cpuLight.02: [mule_mediaupload].so-file-http-request-sendFlow.CPU_LITE #15368f21] [event: b17cd1f0-9e93-11ea-95ae-681401007098] org.mule.runtime.core.internal.processor.LoggerMessageProcessor: {
"success" : false,
"processId" : "CA410762B598945B",
"reasons" : [ {
"code" : 57040122,
"message" : "Input file is missing."
} ]
}
below is the XML
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:http="http://www.mulesoft.org/schema/mule/http"
xmlns:file="http://www.mulesoft.org/schema/mule/file"
xmlns:ee="http://www.mulesoft.org/schema/mule/ee/core"
xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd">
<file:config name="File_Config" doc:name="File Config" doc:id="0272f407-da7b-46e7-a0e1-8f4edda4e3f9" >
<file:connection workingDir="C:\Files\" />
</file:config>
<http:request-config name="HTTP_Request_configuration" doc:name="HTTP Request configuration" doc:id="00b795c8-285e-445c-9bb0-8001f2ffdaf8" />
<http:request-connection protocol="HTTPS" host=" http://mysuperserver/" />
</http:request-config>
<flow name="so-file-http-request-sendFlow">
<scheduler doc:name="Scheduler" doc:id="d6b797dd-7f26-41eb-8bb9-74456a4606fc" >
<scheduling-strategy >
<fixed-frequency frequency="1" timeUnit="DAYS"/>
</scheduling-strategy>
</scheduler>
<file:read doc:name="Read" config-ref="File_Config" path="medialist.csv"/>
<logger level="INFO" doc:name="Logger" doc:id="2c9bb06a-e935-4469-8282-cef67adc5926" message="#[payload]"/>
<ee:transform doc:name="Transform Message" doc:id="7cc45c6a-9326-49de-bea1-d4c9a29a6b26">
<ee:message >
<ee:set-payload ><![CDATA[%dw 2.0
output multipart/form-data
---
{
parts : {
params : {
headers : {
"Content-Type": "text/plain"
},
content : "{actionType:Import}"
},
file : {
headers : {
"Content-Disposition" : {
"name": "file",
"filename": ",medialist.csv"
},
"Content-Type" : "application/csv"
}
}
}
}]]></ee:set-payload>
</ee:message>
</ee:transform>
<logger level="INFO" doc:name="Logger" doc:id="c5a60159-e14f-436b-8952-efabc3bc07ac" message="#[payload]"/>
<http:request method="POST" doc:name="Request" config-ref="HTTP_Request_configuration1" path="/media/upload/" doc:id="79ccd374-155d-40ca-b848-7e766337f5d3">
<http:headers ><![CDATA[#[output application/java
---
{
Accept : "application/json",
apiAccessKeyId : "username,
apiSecretAccessKey : "Password"
}]]]></http:headers>
</http:request>
<logger level="INFO" doc:name="Logger" doc:id="f2f8ffc4-3520-42d8-bca8-d45100adb144" message="#[payload]"/>
</flow>
</mule>
You are missing the content definition on the file part. Try this:
<ee:transform doc:name="Transform Message" doc:id="7cc45c6a-9326-49de-bea1-d4c9a29a6b26">
<ee:message >
<ee:set-payload ><![CDATA[%dw 2.0
output multipart/form-data
---
{
parts : {
params : {
headers : {
"Content-Type": "text/plain"
},
content : "{actionType:Import}"
},
file : {
headers : {
"Content-Disposition" : {
"name": "file",
"filename": "medialist.csv"
},
"Content-Type" : "application/csv"
},
content: payload
}
}
}]]></ee:set-payload>
</ee:message>
</ee:transform>

Error Propagate/Transform message component doesn't overwrite default behaviour of Mule4

I have create my flows using APIKIT Router. The raml main flow+post://XX flow. Main flow and my POSt flow have Error handler components
MAIN FLOW:
<flow name="raml-main">
<http:listener .....">
<http:response statusCode="#[vars.httpStatus default 200]">
<http:body ><![CDATA[ ]]></http:body>
<http:headers><![CDATA[#[vars.outboundHeaders default {}]]]></http:headers>
</http:response>
<http:error-response statusCode="#[vars.httpStatus default 500]">
<http:body ><![CDATA[#[output application/json --- error.description]]]>
</http:body>
<http:headers><![CDATA[#[vars.outboundHeaders default {}]]]>
</http:headers>
</http:error-response>
</http:listener>
<apikit:router config-ref="raml-config" />
<error-handler>
<on-error-propagate type="APIKIT:BAD_REQUEST">
<logger level="INFO" doc:name="Logger" doc:id="aa51777e-c1c6-42d2-ba68-b51c45c9aeac" message="Im in MAIN FLOWWWW"/>
<ee:transform xsi:schemaLocation="http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd" doc:id="4f00abf2-0b58-419e-8d9a-d3ef60e356ac">
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{message: "BadMAIN request"}]]></ee:set-payload>
</ee:message>
<ee:variables>
<ee:set-variable variableName="httpStatus"><![CDATA[400]]></ee:set-variable>
</ee:variables>
</ee:transform>
</on-error-propagate>
POST FLOW
<flow name="post:\notifications:raml-config">
<json:validate-schema doc:name="Validate schema" doc:id="e447c719-60e2-4f34-aeb9-0b446a1a5eda" schema="schemas/event.json"/>
<choice>
.............................
</choice>
<error-handler >
<on-error-propagate type="JSON:SCHEMA_NOT_HONOURED" enableNotifications="true" logException="true">
<logger level="INFO" doc:name="Logger" doc:id="c818b292-5d89-48eb-aa8d-b7918daa8f0c" message="It is under post flow"/>
<ee:transform xsi:schemaLocation="http://www.mulesoft.org/schema/mule/ee/core http://www.mulesoft.org/schema/mule/ee/core/current/mule-ee.xsd" doc:id="e8fb927d-edb8-405a-b853-600b4788b719">
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{message: "Bad Request"}]]></ee:set-payload>
</ee:message>
<ee:variables>
<ee:set-variable variableName="httpStatus"><![CDATA[400]]></ee:set-variable>
</ee:variables>
</ee:transform>
</on-error-propagate>
</error-handler>
</flow>
If I update payload under Transform processor at POST flow or RAML Main flow, it never gets reflected in the output. Say currently I get 400 bad request.
In the Transform component, if i change message, im not getting my modified message.
Why is that?
<ee:message>
<ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{message: "Bad Request USER ERRROR.."}]]></ee:set-payload>
</ee:message>
RAML CONFIG
/notifications:
post:
headers:
Authorization:
required: false
type: string
responses:
'200':
description: OK
'400':
description: BAD REQUEST
'401':
description: NOT AUTHORIZED
400 means there is no such end point. It means your flow never gets invoked. There is another end point for which Mule is listening.
Luckily Mule reports that url is wrong amd what kind of urls it is listening. Like this
INFO 2020-05-07 07:32:22,539 [http.listener.06 SelectorRunner] org.mule.service.http.impl.service.util.DefaultRequestMatcherRegistry: No listener found for request: (GET)/badurl
INFO 2020-05-07 07:32:22,539 [http.listener.06 SelectorRunner] org.mule.service.http.impl.service.util.DefaultRequestMatcherRegistry: Available listeners are: [([*])/console/*, ([*])/, ([*])/api/*]
Of course if you hit another server or another port or protocol then nothing knows about this request. But, since you have the answer - 400 - then you probably hit your server.
https://simpleflatservice.com/mule4/Recognize400Error.html
Default error handler and response could be also set in the http listener in the Responses - Error Response section
The HTTP response 400 bad request means that the HTTP request is not matching an expected format. It is possible that APIKit is validating the request against the RAML. In that case APIKit will raise the error and it will not execute the post:\notifications:raml-config flow. Have you confirmed the flow is executed, for example with a logger?

Cannot open a new cursor on a closed stream, what does it mean in Mule 4?

I am new to Mulesfot and Mule4 and I am still trying to understand how things works here. Check the following image:
On the first processor I am calling a Salesforce URL and getting an XML back which I am transforming to a JSON in the second processor, there I am storing/outputting the result to a variable SalesforceResponse and later on the third one I am calling a subflow which stores some values on the database. Until that point everything works as expected. The problem comes once I try to access the variable SalesforceResponse in the last processor which I need to get some values as the serverURL for example. Currently I am getting the following error:
Message : Cannot open a new cursor on a closed stream.
Element : SalesforceFlow/processors/3 # salesforcefulfillment:salesforcefulfillment.xml:340 (Transform Message)
Element XML : <ee:transform doc:name="Transform Message" doc:id="bea5898f-5aa8-4835-8e9d-fa1fd165d6d2">
<ee:message></ee:message>
<ee:variables>
<ee:set-variable variableName="SalesforceServerUrl">%dw 2.0
import * from dw::core::URL
var urlComposition = parseURI(vars.SalesforceResponse.serverUrl)
output text/plain
---
log("Houston, we have a problem.")</ee:set-variable>
</ee:variables>
</ee:transform>
Error type : MULE:UNKNOWN
What does error even means? I would expect to be able to access a "session" variable all over the places along the flow without having issues or I can't for some reason that I am not aware of?
Here is the XML definition for the image above:
<sub-flow name="SalesforceFlow" doc:id="237910c7-38c7-42bb-969b-63d6ff03bdaa">
<http:request method="POST" doc:name="Get SF SessionId" doc:id="37908152-700d-4c0e-9b52-b0de25f50fdf" config-ref="HTTP_Request_Salesforce" path="/services/Soap/u/44.0" sendCorrelationId="ALWAYS" outputMimeType="application/xml">
<http:body><![CDATA[#[%dw 2.0
ns soapenv http://schemas.xmlsoap.org/soap/envelope/
ns urn urn:partner.soap.sforce.com
output application/xml
---
soapenv#Envelope: {
soapenv#Body: {
urn#login: {
urn#username: p('SalesforceUsername'),
urn#password: p('SalesforcePassword')
}
}
}]]]>
</http:body>
</http:request>
<ee:transform doc:name="Transform Message" doc:id="b58ed3bd-7d74-4ad1-961f-8bab7a2ff128">
<ee:message>
</ee:message>
<ee:variables>
<ee:set-variable variableName="SalesforceResponse" ><![CDATA[ %dw 2.0
output application/json
ns soap http://schemas.xmlsoap.org/soap/envelope/
---
payload.soap#Envelope.soap#Body.loginResponse.result]]></ee:set-variable>
</ee:variables>
</ee:transform>
<flow-ref doc:name="Log Salesforce Response" doc:id="48326f18-a89b-49b2-ab96-ef2fe7214aaf" name="IntegrationFabricLogsFlow"/>
<ee:transform doc:name="Transform Message" doc:id="bea5898f-5aa8-4835-8e9d-fa1fd165d6d2" >
<ee:message >
</ee:message>
<ee:variables >
<ee:set-variable variableName="SalesforceServerUrl" ><![CDATA[%dw 2.0
import * from dw::core::URL
var urlComposition = parseURI(vars.SalesforceResponse.serverUrl)
output text/plain
---
log("Houston, we have a problem.")]]></ee:set-variable>
</ee:variables>
</ee:transform>
</sub-flow>
Can I get some help to understand how variable definition/access does work in Mule4?

How to convert data from object to string in mule 4?

I used to convert payload to string whenever i need to log the payload on console using the syntax in mule 3 [message.payloadAs(java.lang.String)] and some times used to use object to string converter or object to array converter.
But in mule 4 i don't see any converter as in mule 3 and [message.payloadAs(java.lang.String)] is alos not working.
Please assist me any new syntax of component or consept has come in mule 4 ?
Input
[
{
"firstName": "Ram",
"lastName": "Ram1",
"address": [
{
"street": "a",
"city": "b",
"state": "c"
},
{
"street": "a1",
"city": "b1",
"state": "c1"
}
]
}
Batch Image
Code
<batch:job jobName="Batch_ProcessingBatch_Job" doc:id="2582eccb-720f-499f-99fe-424cab3c9a33" >
<batch:process-records >
<batch:step name="Batch_Step1" doc:id="cb045f6b-edd3-426f-8f28-0d20b301fb6d" >
<logger level="INFO" doc:name="Logger" doc:id="2491184f-e8d7-47b7-bef0-29bafd43247f" message="In Batch_step1........... #[payload]"/>
<batch:aggregator doc:name="Batch Aggregator" doc:id="aa9c1b60-395f-4376-804d-bced200dfb43" size="2">
<set-payload value='#[write(payload, "application/json")]' doc:name="Set Payload" doc:id="9d4b27ee-5692-4a99-a93e-bd7c694f398d" />
<ee:transform doc:name="Transform Message" doc:id="06064422-1352-4ff9-8817-3e87eb1f4264" >
<ee:message >
<ee:set-payload ><![CDATA[%dw 2.0
output application/json
---
payload map(item,index) -> {
name: item.firstName,
surname: item.lastName
}]]></ee:set-payload>
</ee:message>
</ee:transform>
<logger level="INFO" doc:name="Logger" doc:id="c955490e-fab1-436e-8265-f706a577c9d2" message="In Batch_step1 Aggrigator........... #[payload]" />
</batch:aggregator>
</batch:step>
</batch:process-records>
<batch:on-complete >
<logger level="INFO" doc:name="Logger" doc:id="a3923c90-557b-4955-9c40-afd748719abd" message="#['#####It is oncomplete result####': write(payload, "application/json")]"/>
</batch:on-complete>
</batch:job>
Getting Error
Message : "You called the function 'map' with these arguments:
1: String ("[\n \"{\\n \\\"firstName\\\": \\\"Ram\\\",\\n \\\"lastName\\\": \\\"Ram1\...)
2: Function ((item:Any, index:Any) -> ???)
But it expects arguments of these types:
1: Array
2: Function
4| payload map(item,index) -> {
| ...
7| }
Trace:
at map (line: 4, column: 1)
at main (line: 4, column: 9)" evaluating expression: "%dw 2.0
output application/json
---
payload map(item,index) -> {
name: item.firstName,
surname: item.lastName
}".
Error type : MULE:EXPRESSION
Element : Batch_ProcessingFlow/processors/0/route/0/route/0/aggregator/processors/1 # training-1:Batch Processing.xml:27 (Transform Message)
Element XML : <ee:transform doc:name="Transform Message" doc:id="06064422-1352-4ff9-8817-3e87eb1f4264">
<ee:message>
<ee:set-payload>%dw 2.0
output application/json
---
payload map(item,index) -> {
name: item.firstName,
surname: item.lastName
}</ee:set-payload>
</ee:message>
</ee:transform>
(set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
********************************************************************************
After quick googling the new way is to use #[message.payload as String] as shown in link.
You can use the payload.^raw syntax for the loggers. It was introduced in mule 4 and can handles cases where string conversion is needed. Typically pairs well with output text/plain format in a logger.
Ref: https://docs.mulesoft.com/mule-runtime/4.3/dataweave-cookbook-extract-data#metadata_selector
NOTE its never a good idea to log entire payloads (that could contain PII etc..) with maybe an exception where you are building a report that you need to log at the end of your batch process which possibly could be the case here...