I have called a REST api through apache camel and deserialized the same. I need to call another API with the number as the parameter that I have received from calling the previous api. I did it in the following way -
public Collection<String> nos;
from("direct:further").tracing()
.log("body: " body().toString())
.setBody().constant(null)
.setHeader("CamelHttpMethod")
.simple("GET")
.setHeader("Authorization")
.simple("Bearer " "${header.jwt}")
.to("https://call/api/that/returns/numbers")
.choice()
.when().simple("${header.CamelHttpResponseCode} == 200").unmarshal().json(JsonLibrary.Jackson, Abc.class)
.process(
ex->{
Quantity quantity = ex.getIn().getBody(Abc.class);
List<Variations> variationsList = Arrays.stream(quantity.getResources().getVariations()).toList();
nos=variationsList.stream().map(Variations::getNo).collect(
Collectors.toList());
nos.forEach(s -> { //Since nos is a collection of String I would like to iterate through it
String url="https://call/another/api/with/number" "?" s;//the link with the number as the parameter
from("direct:start") //This is not working. I not able to call the url
.setHeader("CamelHttpHeader")
.simple("GET")
.setHeader("Authorization")
.simple("Bearer " "${header.jwt}")
.log("I did call the numbers") //This is also not getting printed
.to(url);
});
}).log("I am out of the loop" body())
.otherwise()
.log("Error!!!");
I am unable to call another api with the number that I received adter calling the first api. How should I do it? I also tried to call it like
from("rest:get:" url).tracing()
.setHeader("CamelHttpHeader")
.simple("GET")
.setHeader("Authorization")
.simple("Bearer " "${header.jwt}")
.log("I did call the numbers").to(url);
But unfortunately the above code also did not work inside the loop. I declared the collection nos outside the method definition. How should I call another API from the numbers stored in nos collection? Should I call another Api outside the lambda function or inside?
CodePudding user response:
Instead of trying to define new routes inside a processor you should store collection of the numbers to body and use split to call dynamic producer endpoint toD
which can use simple language to construct the uri with values from body, headers, properties etc.
If you later need to collect all the responses to say list you can create custom AggregationStrategy or use Flexible ones.
Simple example with Camel 3.18.2 using unit tests
package com.example;
import java.util.ArrayList;
import org.apache.camel.AggregationStrategy;
import org.apache.camel.Exchange;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.AdviceWith;
import org.apache.camel.builder.AggregationStrategies;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.model.dataformat.JsonLibrary;
import org.apache.camel.test.junit5.CamelTestSupport;
import org.junit.jupiter.api.Test;
public class NumbersAPITests extends CamelTestSupport {
@Test
public void testAPILogic() throws Exception {
replaceHttpEndpointWithSimpleResponse("requestNumbersFromAPI",
"[1,2,3,4,5]");
replaceHttpEndpointWithSimpleResponse("requestDataWithIdFromAPI",
"{ \"id\"=\"${body}\", \"data\":\"some data\" }");
weaveAddMockendpointAsLast("requestNumbersFromAPI", "result");
weaveAddMockendpointAsLast("requestDataWithIdFromAPI", "splitResult");
MockEndpoint mockResultEndpoint = getMockEndpoint("mock:result");
mockResultEndpoint.expectedMessageCount(1);
MockEndpoint mockSplitResultEndpoint = getMockEndpoint("mock:splitResult");
mockSplitResultEndpoint.expectedMessageCount(5);
startCamelContext();
template.sendBodyAndHeader("direct:requestNumbersFromAPI", null, "jwt", "not-valid-jwt");
mockResultEndpoint.assertIsSatisfied();
mockSplitResultEndpoint.assertIsSatisfied();
}
@Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder(){
@Override
public void configure() throws Exception {
AggregationStrategy aggregationStrategy = AggregationStrategies
.flexible()
.accumulateInCollection(ArrayList.class);
from("direct:requestNumbersFromAPI")
.routeId("requestNumbersFromAPI")
.setBody().constant(null)
.setHeader("Authorization")
.simple("Bearer " "${header.jwt}")
.to("http://localhost:3001/api/numbers")
.unmarshal().json(JsonLibrary.Jackson, Integer[].class)
.split(body(), aggregationStrategy)
.to("direct:requestDataWithIdFromAPI")
.end()
.to("log:loggerName?showAll=true")
;
from("direct:requestDataWithIdFromAPI")
.routeId("requestDataWithIdFromAPI")
.setHeader("Authorization")
.simple("Bearer " "${header.jwt}")
.convertBodyTo(String.class)
.log("Calling API http://localhost:3001/api/data/${body} with number: ${body}")
.toD("http://localhost:3001/api/data/${body}")
.convertBodyTo(String.class)
;
}
};
}
@Override
public boolean isUseAdviceWith() {
return true;
}
private void replaceHttpEndpointWithSimpleResponse(String routeId, String simpleResponse) throws Exception {
AdviceWith.adviceWith(context(), routeId, a -> {
a.weaveByToUri("http*")
.replace()
.setHeader(Exchange.HTTP_RESPONSE_CODE).constant(200)
.setBody().simple(simpleResponse);
});
}
private void weaveAddMockendpointAsLast(String routeId, String mockName) throws Exception {
AdviceWith.adviceWith(context(), routeId, a -> {
a.weaveAddLast()
.to("mock:" mockName);
});
}
}
The request is getting generated with additional " at the beginning and the end of body parameter. So it is showing failed invoking status- For example - call/another/api/with/number/"8767"= How can I avoid the " to get attached to the body parameter? Jeet
If your data has extra quotation marks that should not get sent to the api you can remove them before calling toD html endpoint:
setBody().exchange(ex -> {
return ex.getMessage().getBody(String.class)
.replace("\"", "");
})