Skip to content

Commit cbf9544

Browse files
feat(cli): allow disabling legacy federation injection for FederationV2 schemas (#10788)
* feat(cli): allow disabling legacy federation injection for Federation v2 schemas * Add changeset --------- Co-authored-by: Eddy Nguyen <ch@eddeee888.me> Co-authored-by: Eddy Nguyen <github@eddeee888.me>
1 parent b933b57 commit cbf9544

4 files changed

Lines changed: 123 additions & 1 deletion

File tree

.changeset/strong-eagles-obey.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-codegen/core': minor
3+
---
4+
5+
Add disableFederationDirectiveAndScalarInjection config to better support Federation v2

packages/graphql-codegen-cli/tests/codegen.spec.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,4 +1505,86 @@ describe('Codegen Executor', () => {
15051505
expect(result.length).toBe(1);
15061506
expect(result[0].content).toContain('export type WpCoreImageBlockForGalleryFragment = ');
15071507
});
1508+
1509+
describe('Federation', () => {
1510+
it('should include federation directives and scalar when federation: true ', async () => {
1511+
const { result } = await executeCodegen({
1512+
schema: [SIMPLE_TEST_SCHEMA],
1513+
generates: {
1514+
'out1.graphql': {
1515+
plugins: ['schema-ast'],
1516+
},
1517+
},
1518+
config: {
1519+
federation: true,
1520+
},
1521+
});
1522+
1523+
expect(result[0].content).toContain('directive @external on FIELD_DEFINITION');
1524+
expect(result[0].content).toContain(
1525+
'directive @requires(fields: _FieldSet!) on FIELD_DEFINITION',
1526+
);
1527+
expect(result[0].content).toContain(
1528+
'directive @provides(fields: _FieldSet!) on FIELD_DEFINITION',
1529+
);
1530+
expect(result[0].content).toContain(
1531+
'directive @key(fields: _FieldSet!) on OBJECT | INTERFACE',
1532+
);
1533+
expect(result[0].content).toContain('scalar _FieldSet');
1534+
});
1535+
it('should not include federation directives and scalar when federation: true and disableFederationDirectiveAndScalarInjection: true', async () => {
1536+
const { result } = await executeCodegen({
1537+
schema: [SIMPLE_TEST_SCHEMA],
1538+
generates: {
1539+
'out1.graphql': {
1540+
plugins: ['schema-ast'],
1541+
},
1542+
},
1543+
config: {
1544+
federation: true,
1545+
disableFederationDirectiveAndScalarInjection: true,
1546+
},
1547+
});
1548+
1549+
expect(result[0].content).not.toContain('directive @external on FIELD_DEFINITION');
1550+
expect(result[0].content).not.toContain(
1551+
'directive @requires(fields: _FieldSet!) on FIELD_DEFINITION',
1552+
);
1553+
expect(result[0].content).not.toContain(
1554+
'directive @provides(fields: _FieldSet!) on FIELD_DEFINITION',
1555+
);
1556+
expect(result[0].content).not.toContain(
1557+
'directive @key(fields: _FieldSet!) on OBJECT | INTERFACE',
1558+
);
1559+
expect(result[0].content).not.toContain('scalar _FieldSet');
1560+
expect(result[0].content).toContain('type MyType');
1561+
});
1562+
it('should not include federation directives and scalar when federation: false and disableFederationDirectiveAndScalarInjection: true', async () => {
1563+
const { result } = await executeCodegen({
1564+
schema: [SIMPLE_TEST_SCHEMA],
1565+
generates: {
1566+
'out1.graphql': {
1567+
plugins: ['schema-ast'],
1568+
},
1569+
},
1570+
config: {
1571+
federation: false,
1572+
disableFederationDirectiveAndScalarInjection: true,
1573+
},
1574+
});
1575+
1576+
expect(result[0].content).not.toContain('directive @external on FIELD_DEFINITION');
1577+
expect(result[0].content).not.toContain(
1578+
'directive @requires(fields: _FieldSet!) on FIELD_DEFINITION',
1579+
);
1580+
expect(result[0].content).not.toContain(
1581+
'directive @provides(fields: _FieldSet!) on FIELD_DEFINITION',
1582+
);
1583+
expect(result[0].content).not.toContain(
1584+
'directive @key(fields: _FieldSet!) on OBJECT | INTERFACE',
1585+
);
1586+
expect(result[0].content).not.toContain('scalar _FieldSet');
1587+
expect(result[0].content).toContain('type MyType');
1588+
});
1589+
});
15081590
});

packages/graphql-codegen-core/src/codegen.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,20 @@ export async function codegen(options: Types.GenerateOptions): Promise<string> {
5858
}
5959

6060
const federationInConfig: boolean = pickFlag('federation', options.config);
61+
/**
62+
* @description When set to `true`, it disables the automatic injection of legacy Federation v1 directives and scalars (such as `@key`, `@external`, and `_FieldSet`).
63+
*/
64+
const disableFederationDirectiveAndScalarInjection: boolean = pickFlag(
65+
'disableFederationDirectiveAndScalarInjection',
66+
options.config,
67+
);
6168
const isFederation = prioritize(federationInConfig, false);
6269

63-
if (isFederation && !hasFederationSpec(options.schemaAst || options.schema)) {
70+
if (
71+
isFederation &&
72+
!disableFederationDirectiveAndScalarInjection &&
73+
!hasFederationSpec(options.schemaAst || options.schema)
74+
) {
6475
additionalTypeDefs.push(federationSpec);
6576
}
6677

website/src/pages/docs/integrations/federation.mdx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,27 @@ export default config
2626

2727
It will add the required GraphQL directives to your codegen schema and generate a compatible
2828
resolvers signature for [Apollo Federation](https://the-guild.dev/graphql/hive/federation).
29+
30+
For schemas using Apollo Federation v2, the automatic injection of legacy Federation v1 definitions
31+
(such as `scalar _FieldSet`) can cause duplicate definition errors during validation.
32+
33+
To resolve this, set `disableFederationDirectiveAndScalarInjection` to true in your configuration.
34+
This suppresses the automatic injection of legacy directives and scalars, ensuring full
35+
compatibility with Federation v2 schemas and preventing validation failures.
36+
37+
```ts
38+
import { CodegenConfig } from '@graphql-codegen/cli'
39+
40+
const config: CodegenConfig = {
41+
schema: '<path_to_your_schema>',
42+
config: {
43+
federation: true,
44+
disableFederationDirectiveAndScalarInjection: true
45+
},
46+
generates: {
47+
// ...
48+
}
49+
}
50+
51+
export default config
52+
```

0 commit comments

Comments
 (0)