javalearner
javalearner

Reputation: 23

How to replace variables in GraphQL query using Camel GraphQL component

I'm trying to build a camel route to consume the message from ActiveMQ and extract some JSON fields and send the extracted payload to graphql server. I followed graphql component documentation, however, I was unable to figure out how to get the variable values dynamically from the exchange.

# bookByIdQuery.graphql
query($id : String!) {
  book(id :$id) {
    id
    name
  }
}

@BindToRegistry("bookByIdQueryVariables")
public JsonObject bookByIdQueryVariables() {
    JsonObject variables = new JsonObject();
    variables.put("id", "book-1");
    return variables;
}

from("direct:start")
    .to("graphql://http://example.com/graphql?queryFile=bookByIdQuery.graphql&variables=#bookByIdQueryVariables")

In the above example, I want to get the variable value from the exchange. I mean book-1 I need to get from exchange. For that, I made the method to accept the exchange as a parameter, however it does not replace the values in the query. I tried to debug and seen the exchange as null and bookByIdQueryVariables bean is found in context. Seems like there is no converter to convert the bookByIdQueryVariables type to a JSON object. Please suggest if there is a problem in graphql query or variable bean. Any help is appreciated

Upvotes: 1

Views: 1139

Answers (2)

betelgeuse
betelgeuse

Reputation: 160

You can use the variablesHeader available in the graphQl Camel Component.

variablesHeader docs

Here is an example

from(direct("fetchData"))
        .setHeader("queryVariables").method(EventUtil.class, "getMyQuery")
        .toD(graphql("{{api.url}}")
                .queryFile("myQuery.graphql")
                .variablesHeader("queryVariables"))

EventUtil is a classic Spring bean which exposes a method to return a fresh JsonObject instance. That instance can be populated with dynamic data retrieved from current body/exchange

public JsonObject getMyQuery(String body) {
    JsonObject variables = new JsonObject();
    variables.put("queryParam", body);
    return variables;
}

Body flowing through the pipeline in this case is a String but can be whatever you want. You can also request the entire Camel Exchange instance in the signature of that method.

With this solution, multithreading is handled correctly.

Enjoy.

Upvotes: 0

t3h_b0t
t3h_b0t

Reputation: 130

You can lookup bookByIdQueryVariables object in registry, which can be obtained from camel context, and replace it with exchange message body (or whatever you want):

from("direct:start")
    .process(exchange -> {
        String body = exchange.getIn().getBody(String.class);
        Registry registry = exchange.getContext().getRegistry();
        JsonObject variables = registry.lookupByNameAndType("bookByIdQueryVariables", JsonObject.class);
        variables.put("id", body);
    })
    .to("graphql://http://example.com/graphql?queryFile=bookByIdQuery.graphql&variables=#bookByIdQueryVariables")

EDIT:

as Chin Huang mentioned, depending on the context, it might be unsafe to follow this approach, because we're mutating shared value in the registry. In context of synchronous routes it should be pretty safe, but if it's intended to use in multithreaded/concurrent environment then it most likely won't be a good solution.

Upvotes: 0

Related Questions