All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.graphql_java_generator.client.QueryExecutorImpl Maven / Gradle / Ivy

There is a newer version: 2.0RC1
Show newest version
/**
 * 
 */
package com.graphql_java_generator.client;

import java.io.IOException;
import java.util.List;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.graphql_java_generator.client.request.InputParameter;
import com.graphql_java_generator.client.request.ObjectResponse;
import com.graphql_java_generator.client.response.GraphQLExecutionException;
import com.graphql_java_generator.client.response.GraphQLResponseParseException;
import com.graphql_java_generator.client.response.JsonResponseWrapper;

/**
 * This class is the query executor : a generic class, reponsible for calling the GraphQL server, for query, mutation
 * and subscription.
* It has one major parameter: the GraphQL endpoint. See the {@link #QueryExecutorImpl(String)} for more information. * * @author EtienneSF */ public class QueryExecutorImpl implements QueryExecutor { /** Logger for this class */ private static Logger logger = LogManager.getLogger(); /** The Jersey {@link Client}, used to execute the request toward the GraphQL server */ Client client; /** The Jersey {@link WebTarget}, used to execute the request toward the GraphQL server */ WebTarget webTarget; /** * This constructor expects the URI of the GraphQL server. This constructor works only for http servers, not for * https ones.
* For example: http://my.server.com/graphql * * @param graphqlEndpoint * the http URI for the GraphQL endpoint */ public QueryExecutorImpl(String graphqlEndpoint) { if (graphqlEndpoint.startsWith("https:")) { throw new IllegalArgumentException( "This GraphQL endpoint is an https one. Please provide the SSLContext and HostnameVerifier items, by using the relevant Query/Mutation/Subscription constructor"); } client = ClientBuilder.newClient(); webTarget = client.target(graphqlEndpoint); } /** * This constructor expects the URI of the GraphQL server. This constructor works only for http servers, not for * https ones.
* For example: https://my.server.com/graphql * * @param graphqlEndpoint * the https URI for the GraphQL endpoint * @param sslContext * @param hostnameVerifier */ public QueryExecutorImpl(String graphqlEndpoint, SSLContext sslContext, HostnameVerifier hostnameVerifier) { if (graphqlEndpoint.startsWith("http:")) { throw new IllegalArgumentException( "This GraphQL endpoint is an http one. Please use the relevant Query/Mutation/Subscription constructor (without the SSLContext and HostnameVerifier parameters)"); } client = ClientBuilder.newBuilder().sslContext(sslContext).hostnameVerifier(hostnameVerifier).build(); webTarget = client.target(graphqlEndpoint); } /** {@inheritDoc} */ @Override public T execute(String requestType, ObjectResponse objectResponse, List parameters, Class valueType) throws GraphQLExecutionException { String request = null; try { // Let's build the GraphQL request, to send to the server request = buildRequest(requestType, objectResponse, parameters); logger.trace(GRAPHQL_MARKER, "Generated GraphQL request: {}", request); return doJsonRequestExecution(request, valueType); } catch (IOException e) { throw new GraphQLExecutionException("Error when executing query <" + request + ">: " + e.getMessage(), e); } } /** {@inheritDoc} */ @Override public T execute(String query, Class valueType) throws IOException, GraphQLExecutionException { return doJsonRequestExecution(query, valueType); } /** * Executes the given json request, and returns the server response mapped into the relevant java classes. * * @param * The GraphQL type to map the response into * @param jsonRequest * The json request to send to the server, as is. * @param valueType * The GraphQL type to map the response into * @return * @throws IOException * @throws GraphQLExecutionException */ T doJsonRequestExecution(String jsonRequest, Class valueType) throws IOException, GraphQLExecutionException { Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON); invocationBuilder.header("Accept", MediaType.APPLICATION_JSON); JsonResponseWrapper response = invocationBuilder.post(Entity.entity(jsonRequest, MediaType.APPLICATION_JSON), JsonResponseWrapper.class); if (logger.isTraceEnabled()) { ObjectMapper objectMapper = new ObjectMapper(); logger.trace("Parsed response data: {}", objectMapper.writeValueAsString(response.data)); logger.trace("Parsed response errors: {}", objectMapper.writeValueAsString(response.errors)); } if (response.errors == null || response.errors.size() == 0) { // No errors. Let's parse the data ObjectMapper mapper = new ObjectMapper(); return mapper.treeToValue(response.data, valueType); } else { int nbErrors = 0; String agregatedMessage = null; for (com.graphql_java_generator.client.response.Error error : response.errors) { String msg = error.toString(); nbErrors += 1; logger.error(GRAPHQL_MARKER, msg); if (agregatedMessage == null) { agregatedMessage = msg; } else { agregatedMessage += ", "; agregatedMessage += msg; } } if (nbErrors == 0) { throw new GraphQLExecutionException("An unknown error occured"); } else { throw new GraphQLExecutionException(nbErrors + " errors occured: " + agregatedMessage); } } } /** * Builds a single GraphQL request from the parameter given. * * @param requestType * One of "query", "mutation" or "subscription" * @param objectResponse * Defines what response is expected from the server. The {@link ObjectResponse#getFieldAlias()} method * returns the field of the query, that is: the query name. * @param parameters * @return The GraphQL request, ready to be sent to the GraphQl server. */ String buildRequest(String requestType, ObjectResponse objectResponse, List parameters) { if (!requestType.equals("query") && !requestType.equals("mutation") && !requestType.equals("subscription")) { throw new IllegalArgumentException( "requestType must be one of \"query\", \"mutation\" or \"subscription\", but is \"" + requestType + "\""); } StringBuilder sb = new StringBuilder(); sb.append(requestType).append(" "); sb.append("{"); sb.append(objectResponse.getFieldName()); if (parameters != null && parameters.size() > 0) { sb.append("("); boolean writeComma = false; for (InputParameter param : parameters) { if (writeComma) sb.append(", "); writeComma = true; sb.append(param.getName()).append(": ").append(param.getValueForGraphqlQuery()); } // for sb.append(")"); } objectResponse.appendResponseQuery(sb); sb.append("}"); return "{\"query\":\"" + sb.toString() + "\",\"variables\":null,\"operationName\":null}"; } /** * Parse the GraphQL server response, and map it to the objects, generated from the GraphQL schema. * * @param * * @param rawResponse * @param objectResponse * @return * @throws GraphQLResponseParseException * @throws IOException */ T parseResponse(String rawResponse, ObjectResponse objectResponse, Class valueType) throws GraphQLResponseParseException, IOException { // Let's read this response with Jackson ObjectMapper mapper = new ObjectMapper(); JsonNode node = mapper.readTree(rawResponse); // The main node should be unique, named data, and be a container if (node.size() != 1) throw new GraphQLResponseParseException( "The response should contain one root element, but it contains " + node.size() + " elements"); JsonNode data = node.get("data"); if (data == null) throw new GraphQLResponseParseException("Could not retrieve the 'data' node"); JsonNode hero = data.get("hero"); if (hero == null) throw new GraphQLResponseParseException("Could not retrieve the 'hero' node"); return mapper.treeToValue(hero, valueType); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy