Skip to content

Commit

Permalink
fix(federation): consider orphan types as shared types for all subgra…
Browse files Browse the repository at this point in the history
…phs (#5946)

* fix(federation): consider orphan types as shared types for all subgraphs

* Improve
  • Loading branch information
ardatan committed Feb 29, 2024
1 parent a6dd5a2 commit 107c021
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/real-buckets-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@graphql-tools/federation": patch
---

If an interface or scalar type is not annotated for a subgraph explicitly, consider them as a shared type
20 changes: 18 additions & 2 deletions packages/federation/src/supergraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ export function getSubschemasFromSupergraphSdl({
function TypeWithFieldsVisitor(typeNode: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode) {
// TODO: Temporary fix to add missing join__type directives to Query
if (
typeNode.name.value === 'Query' &&
(typeNode.name.value === 'Query' ||
typeNode.name.value === 'Mutation' ||
typeNode.kind === Kind.INTERFACE_TYPE_DEFINITION) &&
!typeNode.directives?.some(directiveNode => directiveNode.name.value === 'join__type')
) {
(typeNode as any).directives = [
Expand Down Expand Up @@ -218,7 +220,9 @@ export function getSubschemasFromSupergraphSdl({
});
}
});
fieldDefinitionNodesByGraphName.set(graphName, fieldDefinitionNodesOfSubgraph);
if (fieldDefinitionNodesOfSubgraph.length > 0 || typeNode.name.value === 'Query') {
fieldDefinitionNodesByGraphName.set(graphName, fieldDefinitionNodesOfSubgraph);
}
}
}
});
Expand Down Expand Up @@ -276,7 +280,9 @@ export function getSubschemasFromSupergraphSdl({
}
visit(ast, {
ScalarTypeDefinition(node) {
let isShared = !node.name.value.startsWith('link__') && !node.name.value.startsWith('join__');
node.directives?.forEach(directiveNode => {
isShared = false;
if (directiveNode.name.value === 'join__type') {
directiveNode.arguments?.forEach(argumentNode => {
if (argumentNode.name.value === 'graph' && argumentNode?.value?.kind === Kind.ENUM) {
Expand All @@ -296,6 +302,16 @@ export function getSubschemasFromSupergraphSdl({
});
}
});
if (isShared) {
subgraphNames.forEach(graphName => {
let subgraphTypes = subgraphTypesMap.get(graphName);
if (!subgraphTypes) {
subgraphTypes = [];
subgraphTypesMap.set(graphName, subgraphTypes);
}
subgraphTypes.push(node);
});
}
},
InputObjectTypeDefinition(node) {
node.directives?.forEach(directiveNode => {
Expand Down
79 changes: 79 additions & 0 deletions packages/federation/test/__snapshots__/supergraphs.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -514,3 +514,82 @@ union _Entity = User | Foo | Bar
scalar _Any"
`;

exports[`Supergraphs d.graphql matches: d.graphql - stitchedSchema 1`] = `
"schema {
query: Query
mutation: Mutation
}
type Query {
getAuthor: ReactionAuthor
}
scalar Url
interface Node {
id: ID!
}
type Mutation {
setNumber: Int
}
type ReactionAuthor implements Node {
avatarUrl: Url!
displayName: String!
id: ID!
}"
`;

exports[`Supergraphs d.graphql subgraphs: d.graphql - NODERESOLVER 1`] = `
"schema {
query: Query
}
type Query {
_entities(representations: [_Any!]!): _Entity
}
scalar Url
interface Node {
id: ID!
}
union _Entity
scalar _Any"
`;

exports[`Supergraphs d.graphql subgraphs: d.graphql - PB_BACKEND 1`] = `
"schema {
query: Query
mutation: Mutation
}
type Mutation {
setNumber: Int
}
type Query {
getAuthor: ReactionAuthor
_entities(representations: [_Any!]!): _Entity
}
scalar Url
interface Node {
id: ID!
}
type ReactionAuthor implements Node {
avatarUrl: Url!
displayName: String!
id: ID!
}
union _Entity = ReactionAuthor
scalar _Any"
`;
64 changes: 64 additions & 0 deletions packages/federation/test/fixtures/supergraphs/d.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
schema
@core(feature: "https://specs.apollo.dev/core/v0.2")
@core(feature: "https://specs.apollo.dev/join/v0.1", for: EXECUTION)
@core(feature: "https://specs.apollo.dev/tag/v0.1") {
query: Query
mutation: Mutation
}

directive @core(as: String, feature: String!, for: core__Purpose) repeatable on SCHEMA

directive @join__field(
graph: join__Graph
provides: join__FieldSet
requires: join__FieldSet
) on FIELD_DEFINITION

directive @join__graph(name: String!, url: String!) on ENUM_VALUE

directive @join__owner(graph: join__Graph!) on INTERFACE | OBJECT

directive @join__type(graph: join__Graph!, key: join__FieldSet) repeatable on INTERFACE | OBJECT

directive @tag(name: String!) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION

type Mutation {
setNumber: Int @join__field(graph: PB_BACKEND)
}

type Query {
getAuthor: ReactionAuthor @join__field(graph: PB_BACKEND)
}

scalar Url

interface Node {
id: ID!
}

type ReactionAuthor implements Node
@join__owner(graph: PB_BACKEND)
@join__type(graph: PB_BACKEND, key: "id") {
avatarUrl: Url! @join__field(graph: PB_BACKEND)
displayName: String! @join__field(graph: PB_BACKEND)
id: ID! @join__field(graph: PB_BACKEND)
}

enum core__Purpose {
"""
`EXECUTION` features provide metadata necessary to for operation execution.
"""
EXECUTION
"""
`SECURITY` features provide metadata necessary to securely resolve fields.
"""
SECURITY
}

scalar join__FieldSet

enum join__Graph {
NODERESOLVER
@join__graph(name: "noderesolver", url: "http://graphql-node-resolver.graphql/graphql")
PB_BACKEND @join__graph(name: "pb-backend", url: "http://pb-backend-web.default/internal/graphql")
}

0 comments on commit 107c021

Please sign in to comment.