apollographql / apollographql/federation
Federated schemas are not compatible with graphql-middleware
- Dominant language
- TypeScript
- Stars
- 725
- Forks
- 276
- Avg merge
- 1h 47m
- Merged PRs (30d)
- 1
Description
👋 hey folks, really appreciate the tooling here, thanks for providing it to the community. I came across a bit of an oddity this week that I'm hoping to discuss.
It appears as though federated schemas are incompatible with some well-known tools in the GraphQL JS ecosystem. I came across this by trying to use [`graphql-middleware`](https://github.com/maticzav/graphql-middleware), but have found that the incompatibility has more to do with [`graphql-js`](https://github.com/graphql/graphql-js) itself.
### The Issue
Executable federated schemas lose their `resolveReference` resolvers when using common schema transform patterns.
I've reproduced the issue with graphql-middleware [here](https://github.com/jgnieuwhof/federation-demo/pull/4/files), and graphql-js [here](https://github.com/jgnieuwhof/federation-demo/pull/3/files).
### Why does this happen?
A common pattern to copy and transform executable schemas, and types, is to use an existing object's configuration to instantiate a new one:
```typescript
const typeA = new GraphQLObjectType(...);
const typeB = new GraphQLObjectType(typeA.toConfig());
```
The executable schema and type `toConfig` methods only return known properties:
https://github.com/graphql/graphql-js/blob/a4e9bc9bb8e05916ac926233394a164b5e129062/src/type/definition.js#L742-L752
The current federation implementation relies on a `resolveReference` property that is injected on the GraphQLObjectType:
https://github.com/apollographql/federation/blob/main/federation-js/src/types.ts#L67-L69
This results in the new object not having the `resolveReference` resolver that it should, since it wasn't officially a part of the originating object's config. This does not result in an error, but rather incorrect runtime behaviour.
### A Potential Solution
Would it be possible to put any federation-specific properties in a schema or type's `extensions`? The `extensions` property is known, and therefore would be included in the transform pattern mentioned above.
Perhaps something like the following:
```typescript
interface ApolloGraphQLObjectTypeExtensions {
resolveReference?: GraphQLReferenceResolver;
}
declare module 'graphql/type/definition' {
interface GraphQLObjectType {
extensions?: {
apollo?: ApolloGraphQLObjectTypeExtensions
}
}
}
```
### Who does this affect?
- [`graphql-middleware`](https://github.com/maticzav/graphql-middleware)
- [`@graphql-tools/schema`](https://github.com/ardatan/graphql-tools/blob/master/packages/schema/src/addResolversToSchema.ts#L367-L375)
- Anyone else transforming executable GraphQL JS schemas using the pattern above
Contributor guide
Research direction
Reproduce the behavior using the linked federation-demo examples, then inspect federation-js/src/types.ts and the referenced graphql-js definition.js section. Compare how resolveReference is attached with the properties preserved by toConfig(). Done means an agreed change prevents resolveReference from being lost during the documented schema transformation patterns.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- graphql, typescript
- Domain
- api, backend-api-design
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100