Skip to content
philipp-gatzka edited this page Dec 26, 2025 · 1 revision

Frequently Asked Questions

Common questions about using Graphite.

General

What is Graphite?

Graphite is a type-safe GraphQL client library for Java/Spring Boot. It generates Java code from your GraphQL schema, providing compile-time type safety and IDE support for building queries.

How does Graphite compare to other GraphQL clients?

Feature Graphite Apollo Android DGS Codegen
Type-safe queries Yes Yes Yes
Spring Boot integration Native Manual Native
Runtime reflection No Minimal Yes
GraalVM support Native Limited Limited
Retry support Built-in Manual Manual
Rate limiting Built-in Manual Manual
Metrics Built-in Manual Partial

What Java version is required?

Java 21 or higher. Graphite uses modern Java features like records and pattern matching.

Is Graphite compatible with GraalVM native image?

Yes. Graphite uses no runtime reflection, making it fully compatible with GraalVM native image compilation.

Schema and Code Generation

How do I get my GraphQL schema?

You need an introspection schema in JSON format. Common ways to obtain it:

  1. graphql-cli: graphql get-schema --endpoint URL --json > schema.json
  2. Postman/Insomnia: Run an introspection query and save the result
  3. GraphQL Playground: Download schema from the UI
  4. Server export: Many GraphQL servers can export their schema

Can I use .graphql schema files?

Currently, Graphite only supports introspection JSON format. Support for SDL (.graphql) files is planned for a future release.

How often should I regenerate code?

Regenerate whenever your GraphQL schema changes. This is typically:

  • After updating the schema file
  • As part of your CI/CD pipeline
  • Before releases

What happens when the schema changes?

  1. Update your local schema file
  2. Regenerate code: ./gradlew graphiteGenerate
  3. Fix any compile errors in your code
  4. Update tests if needed

Breaking changes in the schema will cause compile errors, helping you catch issues early.

Can I customize the generated code?

Currently, the generated code style is fixed. If you need customization, you can:

  • Use interceptors to modify behavior
  • Extend generated classes in your code
  • Request features via GitHub issues

Queries and Mutations

How do I select specific fields?

Use the selection builder:

GetUserQuery.builder()
    .id("123")
    .selecting(s -> s
        .id()
        .name()
        .email()
        // Only these fields will be requested
    )
    .build();

How do I pass variables to a query?

Variables are passed as builder parameters:

GetUserQuery.builder()
    .id("123")          // Variable: $id
    .includeEmail(true) // Variable: $includeEmail
    .build();

Can I use fragments?

Graphite generates flat selection builders. The generated code optimizes queries automatically. For complex selection reuse, create helper methods:

private void selectUserFields(UserSelection s) {
    s.id().name().email();
}

var query = GetUserQuery.builder()
    .selecting(this::selectUserFields)
    .build();

How do I handle nullable fields?

Nullable fields return @Nullable types. Handle them appropriately:

UserDTO user = response.data();
String email = user.email(); // May be null
if (email != null) {
    sendEmail(email);
}

Or use Optional:

Optional.ofNullable(user.email())
    .ifPresent(this::sendEmail);

Error Handling

What's the difference between GraphQL errors and exceptions?

  • GraphQL errors: In the response body, accessible via response.errors(). The request succeeded but had issues.
  • Exceptions: Network failures, timeouts, etc. Thrown as GraphiteException subclasses.

Should I use getData() or getDataOrThrow()?

  • Use getData() when you want to handle errors yourself:

    if (response.hasErrors()) {
        handleErrors(response.errors());
    }
    return response.data();
  • Use getDataOrThrow() when errors should be exceptional:

    return response.getDataOrThrow(); // Throws if errors present

How do I handle partial errors?

GraphQL can return both data and errors. Check for both:

var response = client.execute(query);
if (response.hasErrors()) {
    log.warn("Partial errors: {}", response.errors());
}
if (response.data() != null) {
    processData(response.data());
}

Configuration

How do I configure different environments?

Use Spring profiles:

# application-dev.yml
graphite:
  url: http://localhost:8080/graphql

# application-prod.yml
graphite:
  url: https://api.production.com/graphql

How do I add authentication headers?

Static headers via config:

graphite:
  headers:
    Authorization: Bearer ${TOKEN}

Dynamic headers via interceptor:

client = GraphiteClient.builder()
    .requestInterceptor(req ->
        req.withHeader("Authorization", "Bearer " + getToken()))
    .build();

How do I configure retries?

graphite:
  retry:
    enabled: true
    max-attempts: 3
    initial-delay: 100ms
    multiplier: 2.0
    max-delay: 5s

How do I disable SSL verification for development?

This is not supported directly for security reasons. For development, use:

  • A proper development certificate
  • A local GraphQL server without SSL
  • A proxy that terminates SSL

Testing

How do I mock GraphQL responses in tests?

Use GraphiteMockServer:

try (GraphiteMockServer server = GraphiteMockServer.create()) {
    server.stubQuery("GetUser", Map.of("id", "1", "name", "Test"));

    GraphiteClient client = GraphiteClient.builder()
        .endpoint(URI.create(server.getUrl()))
        .build();

    // Your test code
}

How do I test error handling?

// GraphQL errors
server.stubError("GetUser",
    GraphQLError.builder()
        .message("Not found")
        .build());

// HTTP errors
server.stubHttpError("GetUser", 500);

// Timeouts
server.stubWithDelay("GetUser", 5000, data);

Can I use WireMock directly?

Yes, GraphiteMockServer wraps WireMock:

server.getWireMockServer().stubFor(
    post("/graphql")
        .willReturn(aResponse().withStatus(200))
);

Performance

How can I improve performance?

  1. Connection pooling: Configure appropriate pool size
  2. Async execution: Use executeAsync() for concurrent requests
  3. Field selection: Only request needed fields
  4. Caching: Implement application-level caching
  5. Rate limiting: Prevent server overload

Is Graphite thread-safe?

Yes. GraphiteClient is thread-safe and designed for concurrent use. Create one instance and share it.

Should I create multiple clients?

Usually no. A single GraphiteClient can handle many concurrent requests. Create multiple clients only if you need:

  • Different configurations (timeouts, headers)
  • Connection to different GraphQL servers
  • Isolation for testing

Observability

What metrics are available?

  • graphite.client.requests - Request count by operation/status
  • graphite.client.request.duration - Request timing
  • graphite.client.retry.attempts - Retry counts
  • graphite.http.connections.* - Connection pool metrics

How do I enable tracing?

Add Micrometer Tracing to your classpath:

implementation("io.micrometer:micrometer-tracing")
implementation("io.micrometer:micrometer-tracing-bridge-otel") // or brave

Trace context is propagated automatically.

How do I correlate logs with requests?

Use MDC keys in your log format:

<pattern>%d [%X{graphite.operation}] [%X{graphite.requestId}] %msg%n</pattern>

Migration

How do I migrate from other GraphQL clients?

  1. Add Graphite dependencies
  2. Generate code from your schema
  3. Replace client initialization
  4. Update query calls to use generated builders
  5. Update error handling to use Graphite exceptions
  6. Update tests to use GraphiteMockServer

Can I use Graphite alongside other clients?

Yes. Graphite doesn't conflict with other GraphQL libraries. You can migrate incrementally.

Getting Help

Where can I report bugs?

GitHub Issues

Where can I request features?

GitHub Issues - use the feature request template.

Is commercial support available?

Not currently. For enterprise needs, please open a GitHub issue to discuss.

Clone this wiki locally