GraphQL

Schema files, @TypeController, @Field, the namespace pattern, queries, mutations, subscriptions, and DataLoader batching.

Schema Files

GraphQL schemas are .graphqls files under src/main/resources/graphql/:

graphql

Schema Registration

Each module declares which schema files to load with a @Schemas interface:

kotlin

KSP merges all @Schemas interfaces across all modules into a single unified schema.

TypeController & Fields

@TypeController marks a class as the field resolver for a GraphQL type. The type is inferred from GraphQLController<T>. Each method is annotated with @Field:

kotlin

The first parameter receives the parent object being resolved.

Automatic Parameter Injection

Parameter TypeWhat It Provides
AuthenticationContextAuthenticated user (required — fails if unauthenticated)
AuthenticationContext?Optional auth — null for unauthenticated requests
Batch<K, V>DataLoader batch context
DataFetchingEnvironmentGraphQL Java environment
ServerCallUnderlying HTTP request

All other parameters map to GraphQL field arguments by name.

The Namespace Pattern

Top-level fields return singleton objects, which are resolved by their own @TypeController:

Query controller
Wiring into the tree

This creates the query path: query { content { categories { all { ... } } } }

Mutation Controllers

Mutations follow the same namespace pattern with separate mutation objects:

kotlin
Every mutation follows: Authenticate (non-nullable AuthenticationContext) → Authorize (permission check) → Execute (delegate to service) → Return.

Subscriptions

Subscription fields return Flow<T> backed by PubSubService:

kotlin

Batching (DataLoader)

Use Batch<K, V> in field resolvers to avoid N+1 queries:

kotlin

The ServiceCache batch resolver handles loading all keys in a single query. See Caching for how batch resolvers are declared.