apollographql / apollographql/federation

Federation relation filtering and arguments problems (federation design concerns / feature request)

Open
#359 16 comments 30 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
725
Forks
276
Avg merge
1h 47m
Merged PRs (30d)
1

Description

Hello everybody.

I'm building my own gateway on top of federation protocol (specific needs that can't be handled by apollo's gateway) so digging up things deeply and seeing some problems there.

For resolving relations `__resolveReference` is used. It is designed to return one and only one entity (throws error otherwise). From my perspective this is highly uneficient by itself, making gateway to produce enormous batch queries for fetching collections and/or multiple related entities and produces overcomplication on service side with dataloaders and complex stuff to optimize N+1 queries.

But ok, uneficient and complex, but has some pros (like batching from multiple sources) and can be handled (#2887).

Where real problem is - it makes literally impossible to filter and paginate queries. While some filtering can be done (btw will relation field arguments be passed down by gateway to `_entities` query?) in form of constrains, null-returns and filtering (again, increased complexity), pagination — no deal.

Usecases are obvious. We have a user in `users` service and user has posts in `posts` service. User has hundreds of posts and I want to render his public feed. I need filters (`status: public`) and pagination (`cursor` or `take/skip` based) for this. And now there is no proper way to do this as `__resolveReference` has no idea of collection, it works with only one entity.

Ok, one could say that `users` service should denormalise posts and keep fields needed for filtering and pagination at it's side, but this can work only for simple cases without complex filtering. If I want to fetch all users's posts that are public, published at specific location, with friends tagged and containing photos? "denormalise" entire post? No, filtering logic belongs to service hosting the entity.

Solution is fairly obvious at first glance: `__resolveReference` should be able to return arrays and act somehow like this.
```graphql
extend type User @key(fields: "id") {
id: ID! @external
posts(where: PostsWhereInput, take: Int, skip: Int): [Post!]!
}
```
```js
const resolvers = {
Post: {
__resolveReference(posts, arguments) {
return products.where({id_in: posts.map(({id})=>id), ...arguments.where}, first: arguments.take, skip: arguments.skip); // and this returns array
}
},
}
```

Or maybe a separate resolver alike `__resolveReferenceMany` (but looks kinda ugly).

Maybe this can't work with current internal logic of gateway and needs huge rework. But honestly this is a big concern for building really complex graphs.

Your thoughts?

Contributor guide

Open the contributing guide

Research direction

Start by tracing the federation entry points named in the issue: __resolveReference and the _entities query, then examine how relation field arguments are handled. The issue is done only when a settled approach exists for filtering and paginating related collections, including whether arguments are passed through and whether array resolution is supported.

Written by the indexing model from the issue text.

Assessment

Tech stack
graphql, typescript
Domain
api, backend-api-design, distributed-systems
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.