Posting empty payload - inbound-gateway - spring-integration

I have the following config.
<int-http:inbound-gateway request-channel="RequestChannel"
path="/contractName/-/{resource}/**"
supported-methods="POST,PUT,PATCH,DELETE"
request-payload-type="java.util.LinkedHashMap"
error-channel="ErrorChannel"
id="InboundGateway" >
</int-http:inbound-gateway>
When posting json to the server the payload is transformed to a LinkedHashMap as expected, however in certain cases I need to post a request that has no payload, when posting an empty payload the conversion fails with bad request. Just wondering if there is a simple/quick workaround in the config where I could tell it to skip the conversion if payload is empty. Currently I need to post "{}" for it to work.
Thanks a lot.

The only one way I see is about coding some custom HttpMessageConverter. And I guess that you just need to override a bit MappingJackson2HttpMessageConverter to populate an empty Map for empty request body.

Related

How to parse interaction messages coming from Slack?

I want to parse interaction message requests coming from Slack. This is what Slack says in their docs:
The body of that request will contain a payload parameter. Your app
should parse this payload parameter as JSON.
That seemed straightforward, so I parsed it like so:
JSON.parse(decodeURIComponent(body.split('=')[1]))
However, in the string-fields of the resulting object, I see pluses instead of spaces:
"There+should+not+be+pluses+here"
What am I doing wrong here?
Took a look at their library here, and it turns out, they use node's querystring.parse().
So the parsing procedure should look like this:
JSON.parse(querystring.parse(body).payload)

Azure Logic App: how to make a x-www-form-encoded?

I'm trying to make a request with Content-Type x-www-form-urlencoded that works perfectly in postman but does not work in Azure Logic App I receive a Bad Request response for missing parameters, like I'd not send enything.
I'm using the Http action.
The body value is param1=value1&param2=value2, but I tried other formats.
HTTP Method: POST
URI : https://xxx/oauth2/token
In Headers section, add the below content-type:
Content-Type: application/x-www-form-urlencoded
And in the Body, add:
grant_type=xxx&client_id=xxx&resource=xxx&client_secret=xxx
Try out the below solution . Its working for me .
concat(
'grant_type=',encodeUriComponent('authorization_code'),
'&client_id=',encodeUriComponent('xxx'),
'&client_secret=',encodeUriComponent('xxx'),
'&redirect_uri=',encodeUriComponent('xxx'),
'&scope=',encodeUriComponent('xxx'),
'&code=',encodeUriComponent(triggerOutputs()['relativePathParameters']['code'])).
Here code is dynamic parameter coming from the previous flow's query parameter.
NOTE : **Do not forget to specify in header as Content-Type ->>>> application/x-www-form-urlencoded**
Answering this one, as I needed to make a call like this myself, today.
As Assaf mentions above, the request indeed has to be urlEncoded and a lot of times you want to compose the actual message payload.
Also, make sure to add the Content-Type header in the HTTP action with value application/x-www-form-urlencoded
therefore, you can use the following code to combine variables that get urlEncoded:
concat('token=', **encodeUriComponent**(body('ApplicationToken')?['value']),'&user=', **encodeUriComponent**(body('UserToken')?['value']),'&title=Stock+Order+Status+Changed&message=to+do')
When using the concat function (in composing), the curly braces are not needed.
First of all the body needs to be:
{ param1=value1&param2=value2 }
(i.e. surround with {})
That said, value1 and value2 should be url encoded. If they are a simple string (e..g a_b) then this would be find as is but if it is for exmaple https://a.b it should be converted to https%3A%2F%2Fa.b
The easiest way I found to do this is to use https://www.urlencoder.org/ to convert it. convert each param separately and put the converted value instead of the original one.
Here is the screenshot from the solution that works for me, I hope it will be helpful. This is example with Microsoft Graph API but will work with any other scenario:

Piping a readstream into a writestream does not work

I (as the client) am trying to post an image with restify, and the server just needs to save it.
req.pipe(fs.createWriteStream('test.jpg'));
is not working. An empty file is created but nothing more. It works when I copy req.body into a buffer and then fs.writeFile(...). I have also tried req.body.pipe, but this throws an error.
You're probably using a body parser middleware that is already reading all of the data from the request so there is nothing left to read. Try adjusting the placement of your route handler and/or body parsing middleware if you want to read directly from the request object.
However, that will only work if the request contains only the image data. Typically a request is formatted as multipart/form-data if it contains at least one file, so you cannot just pipe the request and expect image data only.
So something else in your middleware chain, probably restify.bodyParser(), is already streaming the request body into a buffer or string as req.body and you can't stream something twice. Find the middleware and disable it for this route if you want to handle the streaming straight to the filesystem yourself.

Mule - How to send SOAP Web Service Request?

Hi i am doing simple POC in mule.
I have a web service and i want to make it's Client.
It is SOAP web service and i want to send request to it but i am not getting wayout. Please give me some idea.
Following is code:
MULE:
<cxf:configuration name="CXF_Configuration" enableMuleSoapHeaders="true" initializeStaticBusInstance="true" doc:name="CXF Configuration"/>
<flow name="prjvm1" doc:name="prjvm1">
<http:inbound-endpoint address="http://localhost:5678/httpHello" contentType="application/x-www-form-urlencoded" doc:name="HTTP">
<http:body-to-parameter-map-transformer />
</http:inbound-endpoint>
<!-- This logger is just set to show the message accepted from the request -->
<logger level="INFO" message="#[payload]" doc:name="Logger"/>
<cxf:jaxws-client doc:name="VimService"
wsdlLocation="file:/C:/Users/gugla/MuleStudio/workspace/prjvm/bin/service/vService.wsdl"
operation="retrieveServiceContent"
clientClass="com.esxclient.VService"
port="VimPort">
<cxf:jaxb-databinding/>
</cxf:jaxws-client>
<outbound-endpoint address="http://localhost:8080/gep-sped/servicos/ServicoDeCadastroEAgendamento"
doc:name="Generic"
exchange-pattern="request-response"/>
<echo-component doc:name="Echo"/>
</flow>
I am getting exception, but operation is there in WSDL
Message : No such operation: retrieveServiceContent. Failed to route event via endpoint: org.mule.module.cxf.CxfOutboundMessageProcessor. Message payload is of type: ManagedObjectReference
Code : MULE_ERROR--2
--------------------------------------------------------------------------------
Exception stack is:
1. No such operation: retrieveServiceContent (java.lang.Exception)
org.mule.module.cxf.CxfOutboundMessageProcessor:282 (null)
2. No such operation: retrieveServiceContent. Failed to route event via endpoint: org.mule.module.cxf.CxfOutboundMessageProcessor. Message payload is of type: ManagedObjectReference (org.mule.api.transport.DispatchException)
org.mule.module.cxf.CxfOutboundMessageProcessor:150 (http://www.mulesoft.org/docs/site/current3/apidocs/org/mule/api/transport/DispatchException.html)
--------------------------------------------------------------------------------
Root Exception stack trace:
java.lang.Exception: No such operation: retrieveServiceContent
at org.mule.module.cxf.CxfOutboundMessageProcessor.getOperation(CxfOutboundMessageProcessor.java:282)
at org.mule.module.cxf.CxfOutboundMessageProcessor.getMethodFromOperation(CxfOutboundMessageProcessor.java:322)
at org.mule.module.cxf.CxfOutboundMessageProcessor.getMethod(CxfOutboundMessageProcessor.java:259)
+ 3 more (set debug level logging or '-Dmule.verbose.exceptions=true' for everything)
Following is WSDL in operation: I am confused and around 4 days on it as i am new to mule.
<operation name="RetrieveServiceContent">
<input message="vim2:RetrieveServiceContentRequestMsg" />
<output message="vim2:RetrieveServiceContentResponseMsg" />
<fault name="RuntimeFault" message="vim2:RuntimeFaultFaultMsg"/>
</operation>
There are a couple of ways to do this. I prefer to NOT us the way MuleStudio wants you to do it since I never really got that to work. Basically, whenever I create a webservice client my mule-config looks something like this:
<custom-transformer class="nl.thorax.someprogram.transformers.SomeRequestTransformer
<https:outbound-endpoint ref="someEndpoint" >
<cxf:jaxws-client
clientClass="nl.thorax.someprogram.someclass"
wsdlLocation="http://somedomain?wsdl
port="somePort"
operation="someOperation"/>
</https:outbound-endpoint>
<custom-transformer class="nl.thorax.someprogram.transformers.SomeResponseTransformer
Where:
SomeRequestTransformer: a transformer to create your request.
someEndpoint: some endpoint defined in your MuleConfig. In my example, this is https but it could also be plain http.
someclass: Important! This is your client class. It can be generated from a WSDL by free tools like Apache's WSDL2Java. Google is your friend on this.
somePort: The port in your webservice to use. It can usually be found in the WSDL itself or in the client class you generated. The port more or less specifies what operations you can use.
someOperation: The operation you want to use. Make sure it is typed EXACTLY the same as it's definition in the client class. Wrong use of cApItAlS will cause errors!
SomeResponseTransformer: a transformer to do something with your response.
Now, the way I configure the call (and parse the response for that matter) is to use POJOs. My first transformer, the SomeRequestTransformer (based on the AbstractMessageTransformer in the Mule library) has a bit of code looking like this:
public Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException
{
RequestObject request = new RequestObject();
request.setText("Hello!");
message.setPayload(request);
return message;
}
I create the request, set the variables and return it to Mule. The RequestObject is a class generated by WSDL2Java and corresponds to some operation in the WSDL. Parsing the response works pretty much the same way.
Now I know from experience that a lot of webservices do not quite work in the same way. Try to implement my example yourself. If that doesn't work, please provide your Mule-Config and any and all Java classes you may be using.
EDIT:
I've created an example of my method that actually works. The files can be downloaded at our website. Please see the comments in the files. You have to manually create the Mule project, of course.
Points of note for the example:
The XML-representation of the Mule-config can be found in the 'resources' folder in the archive.
The 'nl.example.example' folder contains all the generated JAX-WS files.
The WSDL location in Mule-config has to be changed since it contains an absolute path.
The example creates an endpoint at http://localhost:8088 for you to call. The flow contains a transformer which creates an example call using pre-defined parameters. Then it tries to connect to the webservice. I've used the default address used by SOAPUI when you create a mock service, but this could of course be changed into anything you want. The webservice (supposedly) returns something which is echoed into the user's browser.
In this example, the parameters are actually Strings, since the WSDL-request doesn't contain anything. To figure out what object to pass to the cxf:jaxws-client look at the operation definition which can be found in the Port definition in your generated files.

How to post data using node-curl?

I'm very new to LINUX working with node.js. Its just my 2nd day. I use node-curl for curl request. In the link below I have found example with Get request. Can anybody provide me a Post request example using node-curl.
https://github.com/jiangmiao/node-curl/blob/master/examples/low-level.js
You need to use setopt in order to specify POST options for a cURL request. The options you should start looking at first are CURLOPT_POST and CURLOPT_POSTFIELDS. From the libcurl documentation linked from node-curl:
CURLOPT_POST
A parameter set to 1 tells the library to do a regular HTTP post. This will also make the library use a "Content-Type: application/x-www-form-urlencoded" header. (This is by far the most commonly used POST method).
Use one of CURLOPT_POSTFIELDS or CURLOPT_COPYPOSTFIELDS options to specify what data to post and CURLOPT_POSTFIELDSIZE or CURLOPT_POSTFIELDSIZE_LARGE to set the data size.
Optionally, you can provide data to POST using the CURLOPT_READFUNCTION and CURLOPT_READDATA options but then you must make sure to not set CURLOPT_POSTFIELDS to anything but NULL. When providing data with a callback, you must transmit it using chunked transfer-encoding or you must set the size of the data with the CURLOPT_POSTFIELDSIZE or CURLOPT_POSTFIELDSIZE_LARGE option. To enable chunked encoding, you simply pass in the appropriate Transfer-Encoding header, see the post-callback.c example.
CURLOPT_POSTFIELDS
... [this] should be the full data to post in a HTTP POST operation. You must make sure that the data is formatted the way you want the server to receive it. libcurl will not convert or encode it for you. Most web servers will assume this data to be url-encoded.
This POST is a normal application/x-www-form-urlencoded kind (and libcurl will set that Content-Type by default when this option is used), which is the most commonly used one by HTML forms. See also the CURLOPT_POST. Using CURLOPT_POSTFIELDS implies CURLOPT_POST.
If you want to do a zero-byte POST, you need to set CURLOPT_POSTFIELDSIZE explicitly to zero, as simply setting CURLOPT_POSTFIELDS to NULL or "" just effectively disables the sending of the specified string. libcurl will instead assume that you'll send the POST data using the read callback!
With that information, you should be able add the following options to the low-level example to have it make a POST request:
var fieldsStr = '{}';
curl.setopt('CURLOPT_POST', 1); // true?
curl.setopt('CURLOPT_POSTFIELDS', fieldsStr);
You will need to tweak the contents of fieldsStr to match the format the server is expecting. Per the documentation you may also need to url-encode the data - which should be as simple as using encodeURIComponent according to this post.

Resources