Skip to content

Commit 35a69a1

Browse files
authored
fix: stitching graphql validation (#6864)
1 parent 6cf18b9 commit 35a69a1

File tree

4 files changed

+78
-12
lines changed

4 files changed

+78
-12
lines changed

.changeset/tough-crabs-deny.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'hive': patch
3+
---
4+
5+
Validate schema stitching output sdl. Previously, this caused invalid SDL to be promoted as the latest valid schema version.

integration-tests/tests/cli/__snapshots__/schema.spec.ts.snap

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -781,11 +781,10 @@ exitCode------------------------------------------:
781781
stderr--------------------------------------------:
782782
__NONE__
783783
stdout--------------------------------------------:
784-
✖ Detected 3 errors
784+
✖ Detected 2 errors
785785
786786
- Unknown type User.
787787
- Unknown type: User.
788-
- Unknown type: User.
789788
790789
View full report:
791790
http://__URL__

integration-tests/tests/models/stitching.spec.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ describe('publish', () => {
472472
expect(message).toMatch('Str');
473473
});
474474

475-
test.concurrent('rejected: not composable, breaking changes', async () => {
475+
test.concurrent('rejected: not composable, breaking changes (syntax error)', async () => {
476476
const {
477477
cli: { publish, check },
478478
} = await prepare(ffs);
@@ -508,9 +508,50 @@ describe('publish', () => {
508508
expect: 'rejected',
509509
});
510510

511-
expect(message).toMatch('topProduct');
512511
expect(message).toMatch('Expected Name');
513512
});
513+
514+
test.concurrent('rejected: object type passed to input argument', async () => {
515+
const {
516+
cli: { publish, check },
517+
} = await prepare(ffs);
518+
519+
await publish({
520+
sdl: /* GraphQL */ `
521+
type Query {
522+
topProduct: Product
523+
}
524+
525+
type Product @key(selectionSet: "{ id }") {
526+
id: ID!
527+
name: String
528+
}
529+
`,
530+
serviceName: 'products',
531+
serviceUrl: 'http://products:3000/graphql',
532+
expect: 'latest-composable',
533+
});
534+
535+
await check({
536+
sdl: /* GraphQL */ `
537+
type Query {
538+
topProduct(filter: TopProductFilter): Product
539+
}
540+
541+
type Product @key(selectionSet: "{ id }") {
542+
id: ID!
543+
name: String
544+
}
545+
546+
type TopProductFilter {
547+
year: Int
548+
category: String
549+
}
550+
`,
551+
serviceName: 'products',
552+
expect: 'rejected',
553+
});
554+
});
514555
});
515556
});
516557
});

packages/services/schema/src/composition/stitching.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
import { buildASTSchema, concatAST, DocumentNode, Kind, parse, printSchema } from 'graphql';
1+
import {
2+
buildASTSchema,
3+
concatAST,
4+
DocumentNode,
5+
GraphQLSchema,
6+
Kind,
7+
parse,
8+
printSchema,
9+
validateSchema,
10+
} from 'graphql';
211
import { validateSDL } from 'graphql/validation/validate.js';
312
import { stitchSchemas } from '@graphql-tools/stitch';
413
import { stitchingDirectives } from '@graphql-tools/stitching-directives';
@@ -64,25 +73,37 @@ export async function composeStitching(args: ComposeStitchingArgs) {
6473
.map(schema => validateStitchedSchema(schema))
6574
.flat();
6675

76+
let stitchedSchema: GraphQLSchema | null = null;
6777
let sdl: string | null = null;
68-
try {
69-
sdl = printSchema(
70-
stitchSchemas({
78+
79+
if (errors.length === 0) {
80+
try {
81+
stitchedSchema = stitchSchemas({
7182
subschemas: args.schemas.map(schema =>
7283
buildASTSchema(trimDescriptions(parse(schema.raw)), {
7384
assumeValid: true,
7485
assumeValidSDL: true,
7586
}),
7687
),
77-
}),
88+
});
89+
sdl = printSchema(stitchedSchema);
90+
} catch (error) {
91+
errors.push(toValidationError(error, 'composition'));
92+
}
93+
}
94+
95+
if (stitchedSchema) {
96+
errors.push(
97+
...validateSchema(stitchedSchema).map(error => ({
98+
message: error.message,
99+
source: 'graphql' as const,
100+
})),
78101
);
79-
} catch (error) {
80-
errors.push(toValidationError(error, 'composition'));
81102
}
82103

83104
return {
84105
errors,
85-
sdl,
106+
sdl: errors.length ? null : sdl,
86107
supergraph: null,
87108
contracts: null,
88109
tags: null,

0 commit comments

Comments
 (0)