RemoteSchemaService.java
package io.github.deweyjose.graphqlcodegen.services;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import graphql.ExecutionResult;
import graphql.introspection.IntrospectionResultToSchema;
import graphql.language.Document;
import graphql.schema.idl.SchemaPrinter;
import io.github.deweyjose.graphqlcodegen.Logger;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Map;
import lombok.Builder;
import lombok.Getter;
import lombok.SneakyThrows;
/**
* Service for fetching and converting remote GraphQL schemas, including introspection queries.
*
* <p>This service provides methods to:
*
* <ul>
* <li>Fetch a remote GraphQL schema file via HTTP GET
* <li>Fetch and convert a remote GraphQL schema via introspection (HTTP POST)
* <li>Convert introspection JSON results to GraphQL SDL
* </ul>
*/
public class RemoteSchemaService {
private final HttpClient httpClient;
private final ObjectMapper objectMapper = new ObjectMapper();
/**
* Represents a GraphQL introspection operation, including the query and optional operation name.
*/
@Builder
@Getter
public static class IntrospectionOperation {
/** The GraphQL introspection query string. */
private String query;
/** The operation name for the introspection query (optional). */
private String operationName;
}
/** Constructs a new RemoteSchemaService using Java's built-in HttpClient. */
public RemoteSchemaService() {
this.httpClient = HttpClient.newHttpClient();
}
/**
* Fetches a remote GraphQL schema file via HTTP GET.
*
* @param url the URL of the remote schema file
* @return the contents of the schema file as a String
* @throws IOException if the request fails or returns a non-200 status
* @throws InterruptedException if the thread is interrupted
*/
public String getRemoteSchemaFile(String url) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).GET().build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
Logger.debug("Remote schema file: {}", response.body());
if (response.statusCode() != 200) {
throw new IOException("Failed to get remote schema file: " + response.statusCode());
}
return response.body();
}
/**
* Fetches a remote GraphQL schema via introspection (HTTP POST) and converts it to SDL.
*
* @param url the URL of the GraphQL endpoint
* @param operation the introspection operation (query and operation name)
* @param headers additional HTTP headers to include in the request
* @return the GraphQL schema SDL as a String
*/
@SneakyThrows
public String getIntrospectedSchemaFile(
String url, IntrospectionOperation operation, Map<String, String> headers) {
HttpRequest.Builder builder =
HttpRequest.newBuilder()
.uri(URI.create(url))
.POST(HttpRequest.BodyPublishers.ofString(objectMapper.writeValueAsString(operation)))
.header("Content-Type", "application/json");
if (!headers.isEmpty()) {
headers.forEach(builder::header);
}
HttpRequest request = builder.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
Logger.debug("Introspection results: {}", response.body());
if (response.statusCode() != 200) {
throw new IOException("Failed to get introspection results: " + response.statusCode());
}
Map<String, Object> introspection =
objectMapper.readValue(response.body(), new TypeReference<Map<String, Object>>() {});
return convertIntrospectionToSchema(introspection);
}
/**
* Converts a parsed introspection result (as a Map) to GraphQL SDL.
*
* @param introspection the introspection result as a Map (should contain a "data" key)
* @return the GraphQL schema SDL as a String
*/
public String convertIntrospectionToSchema(Map<String, Object> introspection) {
IntrospectionResultToSchema introspectionResultToSchema = new IntrospectionResultToSchema();
ExecutionResult executionResult =
ExecutionResult.newExecutionResult().data(introspection.get("data")).build();
Document schema = introspectionResultToSchema.createSchemaDefinition(executionResult);
SchemaPrinter schemaPrinter = new SchemaPrinter();
String sdl = schemaPrinter.print(schema);
return sdl;
}
}