Skip to content

Commit 767c0db

Browse files
committed
Prohibit root mutation and subscription types from implementing interfaces
1 parent 60272fc commit 767c0db

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

src/type/__tests__/validation-test.ts

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,34 @@ describe('Type System: A Schema must have Object root types', () => {
195195
expectJSON(validateSchema(schemaWithDef)).toDeepEqual([]);
196196
});
197197

198+
it('accepts a Schema whose query type implements interfaces', () => {
199+
const schema = buildSchema(`
200+
interface SomeInterface {
201+
test: String
202+
}
203+
204+
type Query implements SomeInterface {
205+
test: String
206+
}
207+
`);
208+
expectJSON(validateSchema(schema)).toDeepEqual([]);
209+
210+
const schemaWithDef = buildSchema(`
211+
schema {
212+
query: QueryRoot
213+
}
214+
215+
interface SomeInterface {
216+
test: String
217+
}
218+
219+
type QueryRoot implements SomeInterface {
220+
test: String
221+
}
222+
`);
223+
expectJSON(validateSchema(schemaWithDef)).toDeepEqual([]);
224+
});
225+
198226
it('rejects a Schema without a query type', () => {
199227
const schema = buildSchema(`
200228
type Mutation {
@@ -296,6 +324,53 @@ describe('Type System: A Schema must have Object root types', () => {
296324
]);
297325
});
298326

327+
it('rejects a Schema whose mutation type implements interfaces', () => {
328+
const schema = buildSchema(`
329+
type Query {
330+
field: String
331+
}
332+
333+
interface SomeInterface {
334+
test: String
335+
}
336+
337+
type Mutation implements SomeInterface {
338+
test: String
339+
}
340+
`);
341+
expectJSON(validateSchema(schema)).toDeepEqual([
342+
{
343+
message: 'Root type "Mutation" cannot implement interfaces.',
344+
locations: [{ line: 10, column: 7 }],
345+
},
346+
]);
347+
348+
const schemaWithDef = buildSchema(`
349+
schema {
350+
query: Query
351+
mutation: MutationRoot
352+
}
353+
354+
type Query {
355+
field: String
356+
}
357+
358+
interface SomeInterface {
359+
test: String
360+
}
361+
362+
type MutationRoot implements SomeInterface {
363+
test: String
364+
}
365+
`);
366+
expectJSON(validateSchema(schemaWithDef)).toDeepEqual([
367+
{
368+
message: 'Root type "MutationRoot" cannot implement interfaces.',
369+
locations: [{ line: 15, column: 7 }],
370+
},
371+
]);
372+
});
373+
299374
it('rejects a Schema whose subscription type is an input type', () => {
300375
const schema = buildSchema(`
301376
type Query {
@@ -337,6 +412,54 @@ describe('Type System: A Schema must have Object root types', () => {
337412
]);
338413
});
339414

415+
it('rejects a Schema whose subscription type implements interfaces', () => {
416+
const schema = buildSchema(`
417+
type Query {
418+
field: String
419+
}
420+
421+
interface SomeInterface {
422+
test: String
423+
}
424+
425+
type Subscription implements SomeInterface {
426+
test: String
427+
}
428+
`);
429+
expectJSON(validateSchema(schema)).toDeepEqual([
430+
{
431+
message: 'Root type "Subscription" cannot implement interfaces.',
432+
locations: [{ line: 10, column: 7 }],
433+
},
434+
]);
435+
436+
const schemaWithDef = buildSchema(`
437+
schema {
438+
query: Query
439+
subscription: SubscriptionRoot
440+
}
441+
442+
type Query {
443+
field: String
444+
}
445+
446+
interface SomeInterface {
447+
test: String
448+
}
449+
450+
451+
type SubscriptionRoot implements SomeInterface {
452+
test: String
453+
}
454+
`);
455+
expectJSON(validateSchema(schemaWithDef)).toDeepEqual([
456+
{
457+
message: 'Root type "SubscriptionRoot" cannot implement interfaces.',
458+
locations: [{ line: 16, column: 7 }],
459+
},
460+
]);
461+
});
462+
340463
it('rejects a Schema extended with invalid root types', () => {
341464
let schema = buildSchema(`
342465
input SomeInputObject {

src/type/validate.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,15 @@ function validateRootTypes(context: SchemaValidationContext): void {
156156
getOperationTypeNode(schema, operationType) ??
157157
(rootType as any).astNode,
158158
);
159+
} else if (
160+
operationType !== 'query' &&
161+
rootType.getInterfaces().length > 0
162+
) {
163+
const rootTypeStr = inspect(rootType);
164+
context.reportError(
165+
`Root type "${rootTypeStr}" cannot implement interfaces.`,
166+
rootType.astNode,
167+
);
159168
} else {
160169
rootTypesMap.add(rootType, operationType);
161170
}

0 commit comments

Comments
 (0)