This version reworks the CacheResolver API to hopefully clarify its usage as well as allow more advanced use cases if needed.
ObjectIdGenerator and CacheResolver APIsThis version splits the CacheResolver API in two distinct parts:
ObjectIdGenerator.cacheKeyForObject
CacheResolver.resolveField
CacheKey for objects but it can also be any other data if needed. In that respect, it's closer to a resolver as might be found in apollo-serverPreviously, both methods were in CacheResolver even if under the hood, the code path were very different. By separating them, it makes it explicit and also makes it possible to only implement one of them.
Note: In general, prefer using @typePolicy and @fieldPolicy that provide a declarative/easier way to manage normalization and resolution.
ObjectIdGenerator is usually the most common one. It gives objects a unique id:
type Product {
uid: String!
name: String!
price: Float!
}
// An ObjectIdGenerator that uses the "uid" property if it exists
object UidObjectIdGenerator : ObjectIdGenerator {
override fun cacheKeyForObject(obj: Map<String, Any?>, context: ObjectIdGeneratorContext): CacheKey? {
val typename = obj["__typename"]?.toString()
val uid = obj["uid"]?.toString()
return if (typename != null && uid != null) {
CacheKey.from(typename, listOf(uid))
} else {
null
}
}
}
CacheResolver allows resolving a specific field from a query:
query GetProduct($uid: String!) {
product(uid: $uid) {
uid
name
price
}
}
object UidCacheResolver: CacheResolver {
override fun resolveField(field: CompiledField, variables: Executable.Variables, parent: Map<String, Any?>, parentId: String): Any? {
var type = field.type
if (type is CompiledNotNullType) {
type = type.ofType
}
if (type !is ObjectType) {
// This only works for concrete types
return MapCacheResolver.resolveField(field, variables, parent, parentId)
}
val uid = field.resolveArgument("uid", variables)?.toString()
if (uid != null) {
return CacheKey.from(type.name, listOf(uid))
}
// Always fallback to the default resolver
return MapCacheResolver.resolveField(field, variables, parent, parentId)
}
}
Fetched April 11, 2026