apollographql / apollographql/federation

Federated schemas are not compatible with graphql-middleware

Open
#737 1 comment 6 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.