Home > Enterprise >  How call an api with the parameters obtained from another api in apache camel?
How call an api with the parameters obtained from another api in apache camel?

Time:09-27

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("\"", ""); 
})
  • Related