Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions composition/src/errors/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export function shareableFieldDefinitionsError(parent: ObjectContainer, children
}
if (shareableSubgraphs.length < 1) {
errorMessages.push(
`\n The field "${fieldName}" is defined in the following subgraphs: "${shareableSubgraphs.join('", "')}".` +
`\n The field "${fieldName}" is defined in the following subgraphs: "${[...field.subgraphs].join('", "')}".` +
`\n However, it it is not declared "@shareable" in any of them.`,
);
} else {
Expand Down Expand Up @@ -571,4 +571,12 @@ export function invalidArgumentsError(fieldPath: string, invalidArguments: Inval
`", which is not a valid input type.\n`;
}
return new Error(message);
}
}

export const noQueryRootTypeError = new Error(
`A valid federated graph must have at least one populated query root type.\n` +
` For example:\n` +
` type Query {\n` +
` dummy: String\n` +
` }`
);
5 changes: 5 additions & 0 deletions composition/src/federation/federation-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import {
invalidUnionError,
minimumSubgraphRequirementError,
noBaseTypeExtensionError,
noQueryRootTypeError,
shareableFieldDefinitionsError,
subgraphValidationError,
subgraphValidationFailureErrorMessage,
Expand Down Expand Up @@ -101,6 +102,7 @@ import {
DEFAULT_SUBSCRIPTION,
FIELD_NAME,
INLINE_FRAGMENT,
QUERY,
} from '../utils/string-constants';
import {
doSetsHaveAnyOverlap,
Expand Down Expand Up @@ -1134,6 +1136,9 @@ export class FederationFactory {
container.node.interfaces = this.getAndValidateImplementedInterfaces(container);
definitions.push(container.node);
}
if (!this.parentMap.has(QUERY)) {
this.errors.push(noQueryRootTypeError);
}
if (this.errors.length > 0) {
return { errors: this.errors };
}
Expand Down
68 changes: 50 additions & 18 deletions composition/tests/arguments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,16 @@ describe('Argument federation tests', () => {
subgraphWithArgument('subgraph-b', 'String'),
]);
expect(errors).toBeUndefined();
expect(documentNodeToNormalizedString(federationResult.federatedGraphAST)).toBe(
expect(documentNodeToNormalizedString(federationResult!.federatedGraphAST)).toBe(
normalizeString(
versionTwoBaseSchema +
`type Object {
field(input: String): String
}
versionTwoBaseSchema + `
type Query {
dummy: String!
}

type Object {
field(input: String): String
}
`,
),
);
Expand All @@ -44,10 +48,14 @@ describe('Argument federation tests', () => {
expect(errors).toBeUndefined();
expect(documentNodeToNormalizedString(federationResult!.federatedGraphAST)).toBe(
normalizeString(
versionTwoBaseSchema +
`type Object {
field(input: Float!): String
}
versionTwoBaseSchema + `
type Query {
dummy: String!
}

type Object {
field(input: Float!): String
}
`,
),
);
Expand All @@ -59,12 +67,16 @@ describe('Argument federation tests', () => {
subgraphWithArgumentAndDefaultValue('subgraph-b', 'Int', '1337'),
]);
expect(errors).toBeUndefined();
expect(documentNodeToNormalizedString(federationResult.federatedGraphAST)).toBe(
expect(documentNodeToNormalizedString(federationResult!.federatedGraphAST)).toBe(
normalizeString(
versionTwoBaseSchema +
`type Object {
field(input: Int): String
}
versionTwoBaseSchema + `
type Query {
dummy: String!
}

type Object {
field(input: Int): String
}
`,
),
);
Expand All @@ -78,10 +90,14 @@ describe('Argument federation tests', () => {
expect(errors).toBeUndefined();
expect(documentNodeToNormalizedString(federationResult!.federatedGraphAST)).toBe(
normalizeString(
versionTwoBaseSchema +
`type Object {
field(input: Boolean = false): String
}
versionTwoBaseSchema + `
type Query {
dummy: String!
}

type Object {
field(input: Boolean = false): String
}
`,
),
);
Expand Down Expand Up @@ -144,6 +160,10 @@ describe('Argument federation tests', () => {
interface Interface {
field(requiredInAll: Int!, requiredOrOptionalInAll: String!, optionalInAll: Boolean): String
}

type Query {
dummy: String!
}

type Object implements Interface {
field(requiredInAll: Int!, requiredOrOptionalInAll: String!, optionalInAll: Boolean): String
Expand Down Expand Up @@ -225,6 +245,10 @@ const subgraphWithArgument = (name: string, typeName: string): Subgraph => ({
name,
url: '',
definitions: parse(`
type Query {
dummy: String! @shareable
}

type Object @shareable {
field(input: ${typeName}): String
}
Expand All @@ -235,6 +259,10 @@ const subgraphWithArgumentAndDefaultValue = (name: string, typeName: string, def
name,
url: '',
definitions: parse(`
type Query {
dummy: String! @shareable
}

type Object @shareable {
field(input: ${typeName} = ${defaultValue}): String
}
Expand All @@ -245,6 +273,10 @@ const subgraphA = {
name: 'subgraph-a',
url: '',
definitions: parse(`
type Query {
dummy: String! @shareable
}

interface Interface {
field(requiredInAll: Int!, requiredOrOptionalInAll: String!, optionalInAll: Boolean, optionalInSome: Float): String
}
Expand Down
34 changes: 24 additions & 10 deletions composition/tests/entities.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ describe('Entities federation tests', () => {
const federatedGraph = federationResult!.federatedGraphAST;
expect(documentNodeToNormalizedString(federatedGraph)).toBe(
normalizeString(
versionOneBaseSchema +
`
versionOneBaseSchema + `
type Query {
dummy: String!
}

type Trainer {
id: Int!
details: Details!
Expand All @@ -38,8 +41,12 @@ describe('Entities federation tests', () => {
const federatedGraph = federationResult!.federatedGraphAST;
expect(documentNodeToNormalizedString(federatedGraph)).toBe(
normalizeString(
versionOneBaseSchema +
`
versionOneBaseSchema + `
type Query {
dummy: String!
trainer: Trainer!
}

type Trainer {
id: Int!
details: Details!
Expand All @@ -51,10 +58,6 @@ describe('Entities federation tests', () => {
age: Int!
}

type Query {
trainer: Trainer!
}

type Pokemon {
name: String!
level: Int!
Expand Down Expand Up @@ -167,8 +170,7 @@ describe('Entities federation tests', () => {
const federatedGraph = federationResult!.federatedGraphAST!;
expect(documentNodeToNormalizedString(federatedGraph)).toBe(
normalizeString(
versionOneBaseSchema +
`
versionOneBaseSchema + `
type Trainer {
id: Int!
pokemon: [Pokemon!]!
Expand All @@ -179,6 +181,10 @@ describe('Entities federation tests', () => {
name: String!
level: Int!
}

type Query {
dummy: String!
}

type Details {
name: String!
Expand All @@ -194,6 +200,10 @@ const subgraphA: Subgraph = {
name: 'subgraph-a',
url: '',
definitions: parse(`
type Query {
dummy: String!
}

type Trainer @key(fields: "id") {
id: Int!
details: Details!
Expand Down Expand Up @@ -296,6 +306,10 @@ const subgraphG: Subgraph = {
name: 'subgraph-g',
url: '',
definitions: parse(`
type Query {
dummy: String!
}

extend type Trainer @key(fields: "id") {
id: Int!
details: Details!
Expand Down
41 changes: 30 additions & 11 deletions composition/tests/enums.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { federateSubgraphs, incompatibleSharedEnumError, Subgraph } from '../src';
import { parse } from 'graphql';
import { describe, expect, test } from 'vitest';
import { documentNodeToNormalizedString, normalizeString, versionOneBaseSchema } from './utils/utils';
import { documentNodeToNormalizedString, normalizeString, versionTwoBaseSchema } from './utils/utils';

describe('Enum federation tests', () => {
const parentName = 'Instruction';
Expand All @@ -12,8 +12,11 @@ describe('Enum federation tests', () => {
const federatedGraph = federationResult!.federatedGraphAST;
expect(documentNodeToNormalizedString(federatedGraph)).toBe(
normalizeString(
versionOneBaseSchema +
`
versionTwoBaseSchema + `
type Query {
dummy: String!
}

enum Instruction {
FIGHT
POKEMON
Expand All @@ -31,8 +34,11 @@ describe('Enum federation tests', () => {
const federatedGraph = federationResult!.federatedGraphAST;
expect(documentNodeToNormalizedString(federatedGraph)).toBe(
normalizeString(
versionOneBaseSchema +
`
versionTwoBaseSchema + `
type Query {
dummy: String!
}

enum Instruction {
FIGHT
POKEMON
Expand All @@ -52,8 +58,11 @@ describe('Enum federation tests', () => {
const federatedGraph = federationResult!.federatedGraphAST;
expect(documentNodeToNormalizedString(federatedGraph)).toBe(
normalizeString(
versionOneBaseSchema +
`
versionTwoBaseSchema + `
type Query {
dummy: String!
}

enum Instruction {
FIGHT
}
Expand All @@ -69,11 +78,13 @@ describe('Enum federation tests', () => {
test('that enums must be consistent if used as both an input and output', () => {
const { errors, federationResult } = federateSubgraphs([subgraphC, subgraphD]);
expect(errors).toBeUndefined();
const federatedGraph = federationResult!.federatedGraphAST;
expect(documentNodeToNormalizedString(federatedGraph)).toBe(
expect(documentNodeToNormalizedString(federationResult!.federatedGraphAST)).toBe(
normalizeString(
versionOneBaseSchema +
`
versionTwoBaseSchema + `
type Query {
dummy: String!
}

enum Instruction {
FIGHT
POKEMON
Expand Down Expand Up @@ -103,6 +114,10 @@ const subgraphA: Subgraph = {
name: 'subgraph-a',
url: '',
definitions: parse(`
type Query {
dummy: String! @shareable
}

enum Instruction {
FIGHT
POKEMON
Expand All @@ -125,6 +140,10 @@ const subgraphC = {
name: 'subgraph-c',
url: '',
definitions: parse(`
type Query {
dummy: String! @shareable
}

enum Instruction {
FIGHT
POKEMON
Expand Down
11 changes: 9 additions & 2 deletions composition/tests/inputs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ describe('Input federation tests', () => {
const federatedGraph = federationResult!.federatedGraphAST;
expect(documentNodeToNormalizedString(federatedGraph)).toBe(
normalizeString(
versionOneBaseSchema +
`
versionOneBaseSchema + `
type Query {
dummy: String!
}

input TechnicalMachine {
move: String!
number: Int!
Expand All @@ -35,6 +38,10 @@ const subgraphA: Subgraph = {
name: 'subgraph-a',
url: '',
definitions: parse(`
type Query {
dummy: String!
}

input TechnicalMachine {
move: String!
number: Int!
Expand Down
Loading