Skip to main content
Announcements
Join us at Qlik Connect for 3 magical days of learning, networking,and inspiration! REGISTER TODAY and save!
cancel
Showing results for 
Search instead for 
Did you mean: 
Anonymous
Not applicable

cRest and getting HTTP QUERY PARAMETERS

How can I obtain a QUERY PARM from the headers.

 

Here is my URL: http://localhost:8040/?a=1&b=3&c=5

 

I tried logging this: ${header.a} and nothing showed up

 

I tried this in the cRest component : http://127.0.0.1:8040?a={a},c={c},b={b}  and CXFRS exception.

 

I tried logging this: ${header.http_query} and I get "{a=[1],b=[2],c=[3]}"

Thank you

 

 

Labels (3)
9 Replies
Anonymous
Not applicable
Author

I was able to get the value by ${header.http_query['a']}, but it gave me a value of [1] and I just want 1 without the brackets.

 

Any ideas?

tkitchens
Contributor
Contributor

Did anyone ever answer this. Needing to pass query params to a cRest compnent seems like a VERY basic thing to need to do. I'm also having trouble setting a query param from a header. Tried all variations of using the "simple" Camel language I know of. Stuck.

Anonymous
Not applicable
Author

My solution was to do some coding. 

http://localhost:8090/OrderHistory/Account/S9040/Country/US?format=json&lastname=&serialnumber=&ponumber=&ordernumber=8977315&startdate=&enddate=

 

I have a cSetProperty component that sets all the query parameters to null.

 

Then I added a cProcessor that sets the properties:

System.out.println("HTTP_QUERY: "+ exchange.getIn().getHeader("HTTP_QUERY"));
System.out.println("CamelHttpQuery: "+ exchange.getIn().getHeader("CamelHttpQuery"));

String queryString = exchange.getIn().getHeader("CamelHttpQuery", String.class);
System.out.println("queryString = " + queryString);

if(queryString != null && queryString.length() > 0)
{
 String[] params = queryString.split("&");
 for (String param : params)
 {
  String name = param.split("=")[0];
  String value = param.split("=")[1];
  System.out.println(name + " = " + value);
  if(name.equalsIgnoreCase("lastname"))
  {
   exchange.setProperty("lastName", value);
   System.out.println("Setting: lastName = "+ value);
  }
  else if(name.equalsIgnoreCase("serialnumber"))
  {
   exchange.setProperty("serialNumber", value);
   System.out.println("Setting: serialNumber = "+ value);
  } 
  else if(name.equalsIgnoreCase("ponumber"))
  {
   exchange.setProperty("poNumber", value);
   System.out.println("Setting: poNumber = "+ value);
  } 
  else if(name.equalsIgnoreCase("ordernumber"))
  {
   exchange.setProperty("orderNumber", value);
   System.out.println("Setting: orderNumber = "+ value);
  } 
  else if(name.equalsIgnoreCase("startdate"))
  {
   exchange.setProperty("startDate", value);
   System.out.println("Setting: startDate = "+ value);
  } 
  else if(name.equalsIgnoreCase("endDate"))
  {
   exchange.setProperty("endDate", value);
   System.out.println("Setting: endDate = "+ value);
  } 
 }
}

 

tkitchens
Contributor
Contributor

Thanks for replying so quickly!

 

Hmmmmm.... so, I'm now thinking we may be talking about related, but slightly different issues. For starters, I'm onTalend 6.5.1 and attempting to implement a REST GET consumer for another service in the middle of my own REST route. Because I have a requirement to leverage Talend's Service Activity Monitor to capture requests/replies between my route and the external REST service, I must use the cRest component (the other components do not provide this as an option and custom coding also does not work for this).

 

Where exactly are you setting your: http://localhost:8090/OrderHistory/Account/S9040/Country/US?format=json&lastname=&serialnumber=&ponumber=&ordernumber=8977315&startdate=&enddate=? And, how are you getting cRest to use that as its Endpoint value? Are you saying that you set just the query part of that as the "CamelHttpQuery" header value? Confused here.

 

Within the route, I set a header (say "My_Test_Header"). Let's say the REST GET external call I'm making takes a query param named "myparam". The cRest component's Advanced settings tab is where you're supposed to set the query params for the call. If I set "myparam" to a hardcoded value, the call succeeds. However, no matter how I try to set "myparam" to the value of the "My_Test_Header" header, it fails to resolve and therefore sends garbage to the REST GET endpoint.

 

I've also tried several other options, such as building the entire path with query string in a cProcessor that precedes the cRest component, then setting the cRest's "Relative Path" property to the value of that header. That almost works, but in that case, the cRest (I can see it's cRest, because the header looks just fine when I log it right before the call) component messes up the character encoding for the "?" I placed into the string when it submits the request. I could probably encode the "?" myself and that might work, but we shouldn't have to jump through such hoops. There's no valid reason that the cRest component shouldn't allow for query params to be resolved and set from headers and/or properties. I'd argue that nearly ANY GET endpoint will always require at least one dynamic query param. If the cRest component doesn't allow a straightforward (meaning, the dev doesn't have to go way outside the documentation and hand-code a bunch of stuff you can only know via trial and error), it was a major design flaw, or a bug.

 

Just for grins, I did just try setting the cRest "Relative Path" to this: constant("/mediamanage/group/details?guid=&service_guid=1001&team_guid=a8d0ccaf-8f3d-4cd5-a331-ccbc99301ec6"). Then, setting the "guid" property before the cRest. It didn't resolve - submitted the path exactly as set on cRest. Maybe I'm misunderstanding something. But, this really shouldn't be this hard. 

tkitchens
Contributor
Contributor

So, of all the options I've tried so far, the only one that worked is this: in a cProcessor before the cRest component, I build the ENTIRE URL, including all the query params and values and set the Exchange.DESTINATION_OVERRIDE_URL Camel header to this value. Although this works, this approach also interferes with the values stored by the Service Activity Monitor (SAM), because I believe it ignores the Exchange.DESTINATION_OVERRIDE_URL header for its logging. End result is that the SAM entry no longer is able to show the actual request I submitted to the endpoint, as it does when not using the Exchange.DESTINATION_OVERRIDE_URL. Which makes SAM for this route pretty much useless - all I'll know is that I submitted SOME GET request at time X and whether it succeeded. No way to know what the request was. So, I still need another method.

Anonymous
Not applicable
Author

called from a browser or home client:

http://localhost:8090/OrderHistory/Account/S9040/Country/US?format=json&lastname=&serialnumber=&ponumber=&ordernumber=8977315&startdate=&enddate=

 

Here is my route:

cRest -> cSetProperty -> cProcessor -> cJavaDSLProcessor -> cSetHeader -> cHttp

 

cRest:  endpoint: "/mfg/OrderHistory", RestAPIMapping:GET - URI Pattern - "/Account/{account}/Country/{countryCode}"

 

cSetProperty: "account" Simple "${body[0]}", "countryCode" Simple "${body[1]}", "lastName" Constant null, "serialNumber" Constant null..........

 

cProcessor: is the java code I posted below to populate the properties

 

cJavaDSLProcessor: removes the headers with Code: .removeHeaders("*")

 

cSetHeader: this builds the header to be passed on to a http request: "authorization" Constant context.Svc_TalendUsr, org.apache.camel.Exchange.HTTP_QUERY Simple "format=json&lastname=${exchangeProperty.lastName}&serialnumber=${exchangeProperty.serialNumber}&ponumber=${exchangeProperty.poNumber}&ordernumber=${exchangeProperty.orderNumber}&startdate=${exchangeProperty.startDate}&enddate=${exchangeProperty.endDate}" , org.apache.camel.Exchange.HTTP_PATH Simple "/OrderHistory/Account/${exchangeProperty.account}/Country/${exchangeProperty.countryCode}"

 

cHttp: makes the http call to other service: Uri - context.mfgEndpoint, Client, GET

 

I hope this helps,

Todd

tkitchens
Contributor
Contributor

Thanks Todd. That explanation makes what you're doing much clearer.

 

Unfortunately, the whole exercise I'm undertaking is explicitly to swap all my current cHTTP components with cRest (CXFRS) components, mainly so I can leverage SAM. With cHTTP, I'm used to having to use cProcessors to set up my URL, path and query string (I use a different pattern than you, but we're basically doing similar things). Having said that, there may be something within your solution that might point me in a new direction I haven't tried yet with cRest.

 

Thanks!

Tim

tkitchens
Contributor
Contributor

Todd,

 

In case you'd like another possible solution to this for the cHttp component, let me share how I've done this in the past. 

 

Here's an example of how I setup for a cHttp component in a cProcessor:

 

// I actually pull the URI from a context variable in my implementation
exchange.getIn().setHeader(Exchange.HTTP_URI, "http://myexternalhost");

 

// Note that the GET endpoint my route calls doesn't take any path params (different from the below query params), but I could easily
// programatically set that here on the HTTP_PATH if needed as well.
exchange.getIn().setHeader(Exchange.HTTP_PATH, "/order");

 

// ignoring HOW the "MyGUID" header got set
String guidVal = (String)exchange.getIn().getHeader("MyGUID", String.class);

 

// NOTE: do NOT insert the "?" in the HTTP_QUERY. The cHttp component handles all that.

exchange.getIn().setHeader(Exchange.HTTP_QUERY, "guid=" + guidVal);

 

Now I set the Uri value in the cHttp component to: "http://dummyhost?throwExceptionOnFailure=false&httpClient.soTimeout=10000"

 

This is a not-well-documented feature of the Camel HTTP component. By the way, it will still apply the above "throwExceptionOnFailure" and "httpClient.soTimeout" params as well, as those are really only config options for the HTTP component itself and not intended for the target REST API I'm calling. Other than the "dummyhost" I set as the Uri and the HTTP headers required by the GET endpoint for authorization, I leave the "Parameters" panel on the cHttp component empty. Basically, I build ALL the parts of the call the cHttp will make in a single cProcessor component - by setting the 3 Camel headers above. No need to have the framework do any magic for me.

 

I've done this in the past due to what seems to be the same limitation I'm now seeing on the cRest component - Talend doesn't allow me to set query parameters from exchange headers on the cHttp component panel, so I had to experiment and trial and error to get it to do what I believe it should be capable of doing - which is to enable dynamic values for query params. I just cannot comprehend why the developers believe it's OK to only allow for static values. And, if there's a trick to doing this, it should be clearly documented. We're not trying to do anything at all unique here.

tkitchens
Contributor
Contributor

OK, after trying about a dozen approaches, found one that seems to work with cRest AND preserve my ability to have SAM accurately record my cRest consumer outbound calls:

 

  1. In a cProcessor, I build the HTTP query string. Like so: exchange.getIn().setHeader(Exchange.HTTP_QUERY, "guid=659bc936-bed5-450b-8616-526836422118");
  2. In my cRest component, I set the Relative Path value, like I normally would, NOT attempting to deal with adding the query string here. E.g. constant("/order")
  3. I do NOT provide any query params on the cRest component's Advanced panel.

The GET call is passed correctly and SAM records the full HTTP path, plus query params as I expect. Example: GET[/order?guid=659bc936-bed5-450b-8616-526836422118].

 

So, basically I view this approach, as well as the ones we've been discussing in this thread that work, involve bypassing Talend features and going directly to Camel to do what seem to me to be just typical stuff. And, on top of that, trying not to also break Talend-only features you need - such as SAM logging. But, at least this works.