Only first parameter accepted in camel cxf - apache-camel

I have a cxf server defined in camel.xml as:
<cxf:rsServer id="rsServer" address="http://0.0.0.0:9090/orderservice"
serviceClass="my.pakcage.myClass" />
I have a REST service defined as:
#POST
#Path("/orders/{id}/something")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response changeOrderSomething(#PathParam("id") String orderId, #Body String somethingPayload) {
return null;
}
In Java DSL I have camel route as:
from("rsServer?bindingStyle=Default").log("rsServerlogging: ${body}")
.recipientList(simple("direct-vm:${header.operationName}"));
I am calling POST on /orders/1/something and in the body I am passing a json: {"somethingId":"3"}
Later I have a route which accepts direct-vm:changeOrderSomething and passes it to a processor:
#Override
public void process(Exchange exchange) throws Exception {
String body = exchange.getIn().getBody(String.class);
LOG.info("exchange.getIn body is: {}", body);
}
The problem I am facing is that here in the log, body is only "1" which is the path param, which means I am not getting what I am passing as body in the POST request. If I change the order of parameters in REST service as #Body String somethingPayload, #PathParam("id") String orderId, I am getting the json that I passed but not the path param.
What do I do to get everything that I pass as parameters in REST?
UPDATE
I made a mistake calling an Object[] somewhere so it threw exception:
org.apache.cxf.interceptor.Fault: Failed to invoke method: [0] on null due to: java.lang.IndexOutOfBoundsException: Key: 0 not found in bean: 1 of type: java.lang.String using OGNL path [[0]] while invoking public javax.ws.rs.core.Response my.package.myClass.changeOrderSomething(java.lang.String,java.lang.String) with params [1, {
"somethingId":"3"}]
I think this means that the REST webservice is picking up the parameters, but only the first one is passed on to direct-vm:${header.operationName} somehow. Maybe I am missing something here?

So I figured it out. The input POST body can be put as the first argument. This makes the Exchange object's body as the passed body. The #PathParam or any other parameters can be placed later and accessed through exchange.getIn().getHeader("id") since all such parameters are accessed from headers.

Related

Save out response Body into variable with Apache Camel

i have my WSDL file which i built with apache-cxf and i have created my own RouteBuilder to perform a SOAP request. I receive correctly the response using the .log file, so i see into the console, but i do not understand if i can save the response into a variable, so i can perform my operation.
from("timer://start")
.setBody(routeSettings.body)
.log(CxfConstants.OPERATION_NAME+": "+routeSettings.operationName)
.setHeader(CxfConstants.OPERATION_NAME, constant(routeSettings.operationName))
.log(CxfConstants.OPERATION_NAMESPACE+": "+routeSettings.operationNamespace)
.setHeader(CxfConstants.OPERATION_NAMESPACE, constant(routeSettings.operationNamespace))
.to("cxf://"+routeSettings.endpointURL
+ "?serviceClass="+routeSettings.packageURL
+ "&wsdlURL=/wsdl/"+routeSettings.nameWSDL)
.log("Result: ${body.get(0).toString()}")
.to("log:results");
This is my configure() function, i would like to save the body content into a variable.
This allows you to get access to the response to perform operations:
...
.log("Result: ${body.get(0).toString()}")
.to("log:results");
.process(exchange -> {
MyResponseType myResponse = exchange.getIn().getMandatoryBody(MyResponseType.class)
})

Optional response body for rest client using RESTEasy

I'm writing a POC for Quarkus. I'm using this quick start guide to build a REST client. The REST service I'll be integrating with is third party. Here is a simple example of my current implementation:
#Path("/v1")
#RegisterRestClient
public class EmployeeApi {
#POST
#Path("/employees")
ApiResponse createEmployee(#RequestBody Employee employee)
}
This works fine. The issue I'm having is that the third party API will, depending on success / failure, return a response body. In the scenario it does fail, it provides details in the response body (ApiResponse) on why it was unsuccessful. When it succeeds, it returns nothing. This causes Quarkus to throw the following exception:
javax.ws.rs.ProcessingException: RESTEASY003145: Unable to find a MessageBodyReader of content-type application/octet-stream and type com.test.app.ApiResponse
I've tried to wrap ApiResponse in an Optional type but does not solve the problem. I see absolutely nothing in Quarkus / RESTEasy documentation that would indicate a work-around.
I'm wondering if I should be using javax.ws.rs.core.Response instead.
The problem is JaxRS tries to fit ApiResponse to a default return type being application/octet-stream
You should make sure to specify explicitly that you're returning application/json
This is possible using #Produces(APPLICATION_JSON) on top of your service.
Here is the correct code snippet
#Path("/v1")
#RegisterRestClient
public class EmployeeApi {
#POST
#Path("/employees")
#Produces(APPLICATION_JSON)
ApiResponse createEmployee(#RequestBody Employee employee)
}

Debugging RestEasy RestClient

I am using the framework in quarkus to build a rest client for the mandrill API
#RegisterRestClient
#Path("1.0")
#Produces("application/json")
#Consumes("application/json")
public interface MailService {
#POST
#Path("/messages/send-template.json")
JsonObject ping(JsonObject mandrillInput);
}
This is the relevant portion of my application.properties
com.example.service.MailService/mp-rest/url=https:/mandrillapp.com/api
And my example resource
#Path("/hello")
public class ExampleResource {
#Inject
#RestClient
MailService mailService;
#Produces(MediaType.TEXT_PLAIN)
#GET
public String hello() {
System.out.print("In the API");
JsonObject key = Json.createObjectBuilder().add("key", "ABCD").build();
System.out.println("The json built is "+key);
JsonObject response = mailService.ping(key);
System.out.println("The response is " + response);
return "hello";
}
}
What I saw is that if the API I am calling (Mandrill in this case) returns an error response (If my key is wrong for example), then the variable I am using to store the response doesnt get the response. Instead the REST API I am exposing to my application wrapping around this, gets populated with the response from Mandrill.
Is this expected behaviour? How can I debug the output of a rest client implementation in Quarkus?
The REST API being called is https://mandrillapp.com/api/docs/users.JSON.html#method=ping2
If you want to be able to get the body of the response when an error occurs, I suggest you use javax.ws.rs.core.Response as the response type.
You could also go another route and handle exceptions using ExceptionMapper

Empty response from camel in cxf POJO mode

Below is my routing for a sample web service in camel and cxf.
from("cxf:http://localhost:9000/sampleService?serviceClass=com.sample.CommonIntf")
.id("wsProxy")
.bean(MyBean.class)
Simply I am passing input pojo object to bean. And inside bean I am setting the ws response. Here is the bean class.
#Handler
public SOut handle(SInput sin){
SOut s = new SOut();
s.setName(sin.getName());
s.setSurName("aa");
return s;
}
However althoug I can see input object is converted and delivered the handler method soap response is empty.
Here is my web service signature.
public interface CommonIntf{
SOut sampleMethod(SInput input);
}
My question is although my handler returns response, why response soap is empty ?
I think, you just not set exchange output body (request-reply pattern).
Try to modify your route like this:
from("cxf:http://localhost:9000/sampleService?serviceClass=com.sample.CommonIntf")
.id("wsProxy")
.to("bean:MyBean?method=handle");
MyBean class must be registered in bundle context.
<bean id="MyBean" class="com.sample.MyBean"/>
Try the following , define your CXF endpoint
[as per http://camel.apache.org/schema/cxf/ ] in a endpoint definition bean, in this refer the service class,
and refer the same id (for example wsCxfId)in the Camel route.
So the route will be as follows:
from("cxf:bean:wsCxfId")
.id("wsProxy")
.to("bean:MyBean?method=handle");
Hope this helps.

Angularjs: passing an object to java API

My object is info
info
Date: ""
ids: Array[1]
__proto__: Object
It has all the values and I send it in angular.
On the java side if the input parameter is like
public ResponseEntity<Boolean> update(#RequestBody myObject input) {...}
I get an error: 400 (Bad Request)
HTTP Status 400 -
type Status report
message
description The request sent by the client was syntactically incorrect.
But if in the api I do
public ResponseEntity<Boolean> update(#RequestBody String input) {...}
It works fine! what is wrong with it? myObject does have only
String Date;
String[] ids;
I'm assuming you're sending data from AngularJS using $http.post or $http.put? Angular sends JSON as a string in the request body. I would suggest you decode the JSON into a Java object using a library like Gson (see deserialization).

Resources