spring-projects / spring-projects/spring-graphql
Single-entity @EntityMapping should resolve an empty Mono to a null _Entity (per Federation spec) instead of raising a per-entity error
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 1.6k
- Forks
- 336
- PR merge metrics
- No merged PRs in 30d
Description
What
For a single-entity federated reference resolver:
@EntityMapping
public Mono<Book> book(@Argument String id) {
return repository.findById(id); // Mono.empty() when not found
}
an empty Mono (the idiomatic reactive "not found") is turned into a hard per-entity GraphQL error — "Entity fetcher returned null or completed empty" — rather than resolving that entity to null.
Source: EntitiesDataFetcher.invokeEntityMethod:
return handlerMethod.getEntity(environment, representation)
.switchIfEmpty(Mono.error(new RepresentationNotResolvedException(representation, handlerMethod)))
.onErrorResume((ex) -> resolveException(ex, environment, handlerMethod, index));
Why this is arguably wrong
-
The Apollo Federation subgraph spec defines
_entities(representations: [_Any!]!): [_Entity]!— the list is non-null but its elements are nullable, and the spec states: "Entries in the list can be null if no entity exists for a provided representation." So resolving an unresolvable representation tonullis spec-compliant; erroring is stricter than the spec. -
Mono.empty()is the natural reactive signal for "absent"; converting it to an error is surprising. -
Inconsistency within the framework: the batch form (
List<T>/Mono<List<T>>) already lets anulllist entry become a null entity with no error —EntitiesDataFetcher.applyResultsdoesentities.set(index, null)for a non-ErrorContainer(null) result. So the framework can already emit spec-legal nulls; only the ergonomic single-Monoform cannot.
Impact
A subgraph that references another subgraph's entity by a key that may legitimately not resolve (e.g. content deleted after the reference was recorded) cannot return a spec-compliant null from the single-entity form. It must either pre-validate every key or switch to the batch form purely to obtain null tolerance. At the gateway the per-entity error is surfaced to clients (e.g. graphql-request throws on any GraphQL error, failing the whole operation).
Proposed change
Let the single-entity @EntityMapping (Mono<T>) resolve an empty Mono to a null entity — matching the nullable _Entity element and the batch form — or provide an opt-in for that behaviour.
Repro
An @EntityMapping Mono<T> returning Mono.empty() yields the error "Entity fetcher returned null or completed empty" instead of a null entity.
Environment
- Spring for GraphQL (Spring Boot 4.0.x)
- Apollo Federation v2 (
FederationSchemaFactory)
References
EntitiesDataFetcher.invokeEntityMethod(single) vsapplyResults(batch) —spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntitiesDataFetcher.java- Apollo Federation subgraph spec,
_entitiesfield
Disclaimer
This summary was created with the help of AI during a debugging session on why optional entities throw errors
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read spring-graphql/src/main/java/org/springframework/graphql/data/federation/EntitiesDataFetcher.java, starting with invokeEntityMethod and comparing its single-entity handling with applyResults. Reproduce an @EntityMapping method returning Mono.empty(), then verify that the single-entity form produces a null entity without the per-entity error while existing batch behavior remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- graphql, java, spring
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 72/100