From e62435fb857e214e42b31900887b7b448845391e Mon Sep 17 00:00:00 2001 From: dariuszkuc <9501705+dariuszkuc@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:01:43 -0600 Subject: [PATCH 1/4] fix: include default deprecation reason in the composed supergraph `@deprecated` reason used to be optional in the past and as such it was omitted from the supergraph schema. [Reason is no longer optional](https://github.com/graphql/graphql-spec/pull/1040) so we should always include it (even if it is a default). --- composition-js/src/__tests__/compose.test.ts | 6 +++--- internals-js/src/definitions.ts | 6 ++++++ internals-js/src/print.ts | 9 ++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/composition-js/src/__tests__/compose.test.ts b/composition-js/src/__tests__/compose.test.ts index c07e2e394..83656cef9 100644 --- a/composition-js/src/__tests__/compose.test.ts +++ b/composition-js/src/__tests__/compose.test.ts @@ -54,7 +54,7 @@ describe('composition', () => { type T @key(fields: "k") { k: ID a: Int - b: String + b: String @deprecated } enum E { @@ -149,7 +149,7 @@ describe('composition', () => { { k: ID a: Int @join__field(graph: SUBGRAPH2) - b: String @join__field(graph: SUBGRAPH2) + b: String @join__field(graph: SUBGRAPH2) @deprecated(reason: "No longer supported") } union U @@ -177,7 +177,7 @@ describe('composition', () => { type T { k: ID a: Int - b: String + b: String @deprecated(reason: "No longer supported") } union U = S | T diff --git a/internals-js/src/definitions.ts b/internals-js/src/definitions.ts index 2c1b82558..442a849c6 100644 --- a/internals-js/src/definitions.ts +++ b/internals-js/src/definitions.ts @@ -3260,6 +3260,12 @@ export class Directive< const args = entries.length == 0 ? '' : '(' + entries.map(([n, v]) => `${n}: ${valueToString(v, this.argumentType(n))}`).join(', ') + ')'; return `@${this.name}${args}`; } + + toStringWithDefaultValues(): string { + const entries = Object.entries(this.arguments(true)).filter(([_, v]) => v !== undefined); + const args = entries.length == 0 ? '' : '(' + entries.map(([n, v]) => `${n}: ${valueToString(v, this.argumentType(n))}`).join(', ') + ')'; + return `@${this.name}${args}`; + } } /** diff --git a/internals-js/src/print.ts b/internals-js/src/print.ts index b49803a81..42c31298d 100644 --- a/internals-js/src/print.ts +++ b/internals-js/src/print.ts @@ -24,6 +24,7 @@ import { } from "./definitions"; import { assert } from "./utils"; import { valueToString } from "./values"; +import { GraphQLDeprecatedDirective } from 'graphql/type'; export type PrintOptions = { indentString: string; @@ -235,7 +236,13 @@ function printAppliedDirectives( return ""; } const joinStr = onNewLines ? '\n' + options.indentString : ' '; - const directives = appliedDirectives.map(d => d.toString()).join(joinStr); + const directives = appliedDirectives.map(d => { + if (GraphQLDeprecatedDirective.name === d.name) { + return d.toStringWithDefaultValues(); + } else { + return d.toString(); + } + }).join(joinStr); return onNewLines ? '\n' + options.indentString + directives + (endWithNewLine ? '\n' : '') : ' ' + directives; } From 24a20772cc2a212ea1822d471d35f7bf6d8b37e8 Mon Sep 17 00:00:00 2001 From: dariuszkuc <9501705+dariuszkuc@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:11:46 -0600 Subject: [PATCH 2/4] fix tests --- composition-js/src/__tests__/compose.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composition-js/src/__tests__/compose.test.ts b/composition-js/src/__tests__/compose.test.ts index 83656cef9..c7d26ae10 100644 --- a/composition-js/src/__tests__/compose.test.ts +++ b/composition-js/src/__tests__/compose.test.ts @@ -54,7 +54,7 @@ describe('composition', () => { type T @key(fields: "k") { k: ID a: Int - b: String @deprecated + b: String } enum E { @@ -149,7 +149,7 @@ describe('composition', () => { { k: ID a: Int @join__field(graph: SUBGRAPH2) - b: String @join__field(graph: SUBGRAPH2) @deprecated(reason: "No longer supported") + b: String @join__field(graph: SUBGRAPH2) } union U @@ -177,7 +177,7 @@ describe('composition', () => { type T { k: ID a: Int - b: String @deprecated(reason: "No longer supported") + b: String } union U = S | T @@ -1939,7 +1939,7 @@ describe('composition', () => { const [_, api] = schemas(result); expect(printSchema(api)).toMatchString(` type Query { - a: String @deprecated + a: String @deprecated(reason: "No longer supported") b: String } `); From eccb8eb10b089f13916590dfcd5eec31be5e7276 Mon Sep 17 00:00:00 2001 From: dariuszkuc <9501705+dariuszkuc@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:38:32 -0600 Subject: [PATCH 3/4] changeset --- .changeset/green-chairs-nail.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .changeset/green-chairs-nail.md diff --git a/.changeset/green-chairs-nail.md b/.changeset/green-chairs-nail.md new file mode 100644 index 000000000..409ff2e6b --- /dev/null +++ b/.changeset/green-chairs-nail.md @@ -0,0 +1,12 @@ +--- +"@apollo/composition": patch +"@apollo/federation-internals": patch +--- + +Include default deprecation reason in the composed supergraph + +`@deprecated` reason used to be optional in the past + +`@deprecated` reason used to be optional so if a subgraph does not specify the reason, it is omitted from the supergraph +schema. [Reason is no longer optional](https://github.com/graphql/graphql-spec/pull/1040) so we should always include it +(even if it has a default value). \ No newline at end of file From 56640ca5bcb3d93c1be19dbc53bba3101f531354 Mon Sep 17 00:00:00 2001 From: dariuszkuc <9501705+dariuszkuc@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:39:14 -0600 Subject: [PATCH 4/4] fix changelog message --- .changeset/green-chairs-nail.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/.changeset/green-chairs-nail.md b/.changeset/green-chairs-nail.md index 409ff2e6b..06b387ef5 100644 --- a/.changeset/green-chairs-nail.md +++ b/.changeset/green-chairs-nail.md @@ -5,8 +5,6 @@ Include default deprecation reason in the composed supergraph -`@deprecated` reason used to be optional in the past - `@deprecated` reason used to be optional so if a subgraph does not specify the reason, it is omitted from the supergraph schema. [Reason is no longer optional](https://github.com/graphql/graphql-spec/pull/1040) so we should always include it (even if it has a default value). \ No newline at end of file