I have java object that I would like to pass as a custom header to my request on the http outbound gateway. Below is a snippet
<int:gateway id="service" service-interface="MyService" default-request-channel="requestChannel" default-reply-channel="replyChannel">
<int:method name="doSomething" payload-expression="#args[0] + ',' + #args[1]">
<int:header name="method_name" value="login"/>
<int:header name="service_identifier" value="myService"/>
</int:method>
</int:gateway>
<int:header-enricher input-channel="requestChannel" output-channel="gatewayChannel">
<int:header name="user_context" expression="T(UserContextHolder).getContext()"/>
</int:header-enricher>
<int-http:outbound-gateway request-channel="gatewayChannel" url="myURL" mapped-request-headers="user_context, service_identifier, method_name, HTTP_REQUEST_HEADERS"
http-method="POST" reply-channel="replyChannel"/>
Where UserContext could be a java object
UserContext implements Serializable {
String userId;
RequestParameters params;
ScopeEnum scope;
....
}
The problem I have is header user_context is not mapped in the header. From the logs, I can see that the DefaultHttpHeaderMapper is requesting for a Converter or ConversionService. See below -
09:54:59,488 - WARN main org.springframework.integration.http.support.DefaultHttpHeaderMapper - Header 'X- user_context' with value 'UserContextImpl#5e3ca754' will not be set since it is not a String and no Converter is available. Consider registering a Converter with ConversionService (e.g., <int:converter>)
How do I do this please ?
Thanks!
Standard HTTP headers are in key:value format and both key and value are strings.
You try to send object as a HTTP header value which is not very wise (and almost impossible because there may be some limits on the size of headers - for example 8KB Apache default limit).
You have three options:
Consider not using HTTP outbound gateway and use JMS instead (the best one in my opinion)
Add transformer which will serialize UserContext to String (if it was relatively short string it would be ok, in the other case I'd not recommend it)
Implement custom converter UserContext->String as described in section Datatype Channel Configuration of the spring reference documentation:
http://static.springsource.org/spring-integration/reference/htmlsingle/#channel-configuration
Related
Hi I want to add a query parameter Age = 23
I tried adding
message.inboundProperties.'http.query.params'.Age = '23'
In a expression
<expression-component doc:name="Expression"><![CDATA[message.inboundProperties.'http.query.params'.Age= '23';]]></expression-component>
It won't work.
Inbound properties are Immutable hence you must add it in outbound property to add a query param in your outbound http connector you can use the below
<http:request config-ref="HTTP_Request_Configuration" path="outway" method="POST" doc:name="HTTP">
<http:request-builder>
<http:query-param paramName="Age" value="23"/>
</http:request-builder>
</http:request>
To add properties to an outgoing message they need to be in the outbound scope:
message.outboundProperties.'http.query.params'.Age= '23'
You are trying to modify inbound properties but you can´t, they are inmutable
Properties have two main scopes: inbound and outbound.
Inbound properties are immutable, are automatically generated by the message source and cannot be set or manipulated by the user. They contain metadata specific to the message source that prevents scrambling of data formats or other processing mishaps later in the message’s lifecycle. A message retains its inbound properties only for the duration of the flow; when a message passes out of a flow, its inbound properties do not follow it (see image below).
https://docs.mulesoft.com/mule-fundamentals/v/3.7/mule-message-structure
You must add it to outbound as Ryan said.
What is the best way to support accepting of binary data on an ODataController (in .net)? The binary stream can be large, atleast 2MB. I have a controller derived from ODataController (System.Web.Http.Odata.OdataController).
How can I make this controller accept a Content-Type other than application/json (application/octet-stream perhaps)
I am using a base64 encoded string of the binary data in the upload. Is there a better approach?
What I have currently inside the ODataController is:
[HttpPut]
public float Put(string userId, string userType, [FromBody] string base64data)
Two pain points:
base64data parses as null, unless the string is wrapped in an object. For example, a body like "This is a string" results in a null. The body, "{"value":"This is a string"}" parses fine.
If I send more than 2MB of data, I again receive a null (with no errors).
What is the way to support binary data on an odata endpoint with higher allowed limits and efficient way?
How can I make this controller accept a Content-Type other than
application/json (application/octet-stream perhaps)
Use a custom media type formatter Checkout an example here...
I am using a base64 encoded string of the binary data in the upload.
Is there a better approach?
If you don't want to go through the custom media formatter route then you're better off posting your binary data as multipart/form-data. Sample here
base64data parses as null, unless the string is wrapped in an object.
For example, a body like "This is a string" results in a null. The
body, "{"value":"This is a string"}" parses fine.
This is because the default json media formatter expects a json string. However your custom media type formatter will take of raw string.
If I send more than 2MB of data, I again receive a null (with no
errors).
Because you're exceeding the max limit. You can change that using:
<configuration>
<appSettings>
<add key="aspnet:MaxJsonDeserializerMembers" value="1000" />
</appSettings>
</configuration>
Learn more here http://support.microsoft.com/kb/2661403
When leveraging a Web Api endpoint hosted on a different server, what is the best way to have pagination to avoid excessive serialization and deserialization while still being able to see the total # of matches that were found in the Get request?
Web Api:
[Queryable]
public IQueryable<Customer> Get(string input) {
return _repo.GetCustomers(input).AsQueryable();
}
Controller Code:
HttpResponseMessage response = client.GetAsync("api/customer?input=test&$top=2&$skip=0").Result; // test string
if (response.IsSuccessStatusCode) {
CustomerSearchResultViewModel resultViewModel = new CustomerSearchResultViewModel();
resultViewModel.Customers = response.Content.ReadAsAsync<IEnumerable<Customer>>().Result.ToList();
resultViewModel.TotalResults = resultViewModel.Customers.Count;
}
In this example, the TotalResults will be capped at 2 rather than returning the total # of matches found before pagination.
Is there a way to get the total results out by leveraging OData? If that is not possible, how can I best preserve OData functionality while getting out the number I need?
You can use the OData $inlinecount option. The request would look like,
api/customer?input=test&$top=2&$skip=0&$inlinecount=allpages.
Now, we don't support sending the value of count with the default json and xml formatters out-of-the-box. Your client code is the best example why we have decided not to send it by default. The reason is that the client wouldn't know what to do with the extra count property. Our OData formatter supports $inlinecount option by default as the OData format has clear rules for where the count value fits in the response.
That said, you can do a simple change to support count in your responses. Your client code also has to change though. Refer to this answer for details.
I'm trying to send a POST using Groovy HTTPBuilder but the data I want to send is already URL-encoded so I want HTTPBuilder to POST it as is. I tried the following:
def validationString = "cmd=_notify-validate&" + postData
def http = new HTTPBuilder(grailsApplication.config.grails.paypal.server)
http.request(Method.POST) {
uri.path = "/"
body = validationString
requestContentType = ContentType.TEXT
response.success = { response ->
println response.statusLine
}
}
But it gives me a NullPointerException:
java.lang.NullPointerException
at groovyx.net.http.HTTPBuilder$RequestConfigDelegate.setBody(HTTPBuilder.java:1200)
Since you're using pre-encoded form values you cannot use the default map-based content type encoder. You must specify the content type so the EncoderRegistry knows how to handle the body.
You may create the HttpBuilder with a content type that specifies the body is a URL-encoded string:
def http = new HTTPBuilder(url, ContentType.URLENC)
Or make the request passing the content type explicitly:
http.request(Method.POST, ContentType.URLENC) {
// etc.
For reference, here's how I figured it out--I didn't know before I read the question.
Looked at the request method's API docs to see what the closure was expected to contain. I've used HTTPBuilder only in passing, so I wanted to see what, specifically, the body "should" be, or "may" be, and if the two were different.
The four-arg version of the request method links to the RequestConfigDelegate class and said the options were discussed in its docs.
The RequestConfigDelegate.setBody method, which is what the body setter is, states the body "[...] may be of any type supported by the associated request encoder. That is, the value of body will be interpreted by the encoder associated with the current request content-type."
The request encoder link is to the EncoderRegistry class. It has an encode_form method taking a string and states it "assumes the String is an already-encoded POST string". Sounds good.
The request content-type link was to an HttpBuilder inner class method, RequestConfigDelegate.getRequestContentType, which in turn had a link to the ContentType enum.
That enum has a URLENC value that led me to believe it'd be the best first guess.
I tried the HTTPBuilder ctor taking a content type, and that worked.
Circled back to the request methods and noticed there's a version also taking a content type.
I'd guess the total time was ~5-10 minutes, much shorter than it took to type up what I did. Hopefully it'll convince you, though, that finding this kind of stuff out is possible via the docs, in relatively short order.
IMO this is a critical skill for developers to groom, and make you look like a hero. And it can be fun.
I am working on an app where we have to pass specific web api parameters to a web app using HTTP POST.
eg:
apimethod name
parameter1 value
parameter2 value
So do I use a string or URLEncodedPostData to send that data?
It would be good if u help me with a code eg.
I am using something like this but it doesnt post the data to the server.
Though the response code is ok/200 and I also get get a parsed html response when i read the httpresponse input stream. But the code doesnt post anything. So unable to get the expected response.
_postData.append("method", "session.getToken");
_postData.append( "developerKey", "value");
_postData.append( "clientID", "value");
_httpConnection = (HttpConnection) Connector.open(URL, Connector.READ_WRITE);
String encodedData = _postData.toString();
_httpConnection.setRequestMethod(HttpConnection.POST);
_httpConnection.setRequestProperty("User-Agent", "BlackBerry/3.2.1");
_httpConnection.setRequestProperty("Content-Language", "en-US");
_httpConnection.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
_httpConnection.setRequestProperty("Content-Length",(new Integer(encodedData.length())).toString());
os = _httpConnection.openOutputStream();
os.write(requeststring.getBytes());`
The code you posted above looks correct - although you'll want to do a few more things (maybe you did this already but didn't include it in your code):
Close the outputstream once you've written all the bytes to it
Call getResponseCode() on the connection so that it actually sends the request
POSTed parameters are usually sent in the response BODY, which means URL-encoding them is inappropriate. Quote from the HTTP/1.1 protocol:
Note: The "multipart/form-data" type has been specifically defined
for carrying form data suitable for processing via the POST
request method, as described in RFC 1867 [15].
The post method allows you to use pretty arbitrary message bodies — so it is whatever format the server wants.