Skip to content

Commit

Permalink
Update schemaIsSubgraph to also support non nullable _Service.sdl (
Browse files Browse the repository at this point in the history
…#7274)

Related to
apollographql/apollo-federation-subgraph-compatibility#302

We found a discrepancy in how libraries implement the federation
specification (`_Service.sdl` is `String` in Federation 1 and is
`String` in Federation 2).
I'm doing this PR mostly to check how easy it would be to support both
specs at once, if I understood correctly the code `schemaIsSubgraph`
might also be used outside Apollo Server 😊
  • Loading branch information
patrick91 authored Dec 23, 2022
1 parent 0afa7ca commit 3b0ec85
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/quiet-pears-float.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@apollo/server': patch
---

Update schemaIsSubgraph to also support non nullable \_Service.sdl
122 changes: 122 additions & 0 deletions packages/server/src/__tests__/plugin/schemaIsSubgraph.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { schemaIsSubgraph } from '../../plugin/schemaIsSubgraph';
import { describe, it, expect } from '@jest/globals';

import {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLNonNull,
} from 'graphql';

describe('schemaIsSubgraph', () => {
it('returns false when there is no service field', async () => {
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'QueryType',
fields: {
hello: {
type: GraphQLString,
},
},
}),
});

expect(schemaIsSubgraph(schema)).toBe(false);
});

it('returns false when the sdl field is a not string', async () => {
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'QueryType',
fields: {
_service: {
type: new GraphQLObjectType({
name: '_Service',
fields: {
sdl: {
type: GraphQLInt,
},
},
}),
},
},
}),
});

expect(schemaIsSubgraph(schema)).toBe(false);
});

it('returns false when the sdl field is a scalar', async () => {
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'QueryType',
fields: {
_service: {
type: new GraphQLObjectType({
name: '_Service',
fields: {
sdl: {
type: new GraphQLObjectType({
name: 'Scalar',
fields: {
value: {
type: GraphQLString,
},
},
}),
},
},
}),
},
},
}),
});

expect(schemaIsSubgraph(schema)).toBe(false);
});

it('returns true when the sdl field is a string', async () => {
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'QueryType',
fields: {
_service: {
type: new GraphQLObjectType({
name: '_Service',
fields: {
sdl: {
type: GraphQLString,
},
},
}),
},
},
}),
});

expect(schemaIsSubgraph(schema)).toBe(true);
});

it('returns true when the sdl field is a non nullable string', async () => {
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'QueryType',
fields: {
_service: {
type: new GraphQLObjectType({
name: '_Service',
fields: {
sdl: {
type: new GraphQLNonNull(GraphQLString),
},
},
}),
},
},
}),
});

expect(schemaIsSubgraph(schema)).toBe(true);
});
});
13 changes: 11 additions & 2 deletions packages/server/src/plugin/schemaIsSubgraph.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { GraphQLSchema, isObjectType, isScalarType } from 'graphql';
import {
GraphQLSchema,
isObjectType,
isScalarType,
isNonNullType,
} from 'graphql';

// Returns true if it appears that the schema was appears to be of a subgraph
// (eg, returned from @apollo/subgraph's buildSubgraphSchema). This strategy
Expand All @@ -24,7 +29,11 @@ export function schemaIsSubgraph(schema: GraphQLSchema): boolean {
if (!sdlField) {
return false;
}
const sdlFieldType = sdlField.type;

let sdlFieldType = sdlField.type;
if (isNonNullType(sdlFieldType)) {
sdlFieldType = sdlFieldType.ofType;
}
if (!isScalarType(sdlFieldType)) {
return false;
}
Expand Down

0 comments on commit 3b0ec85

Please sign in to comment.