Skip to content

Commit db167ad

Browse files
committed
[AS-252] gateway: normalize root operation types in reporting
The federation spec allows your backends to use any name for their root types (not just the standard Query/Mutation/Subscription) but the composed schema will always use the standard names. Both Apollo-maintained implementations of federated trace reporting (apollo-engine-reporting and federation-jvm) include the backend's potentially nonstandard name in the federated traces sent to the gateway. Then the gateway continues to use those names in the traces it sends to AGM. For example, one of AGM's own implementing services uses QueryRoot, so traces produced by the gateway in front of it have `QueryRoot` on the traces despite that type not actually being part of the composed schema. The effect is that field stats (on the schema explorer) for all root fields are empty! Because normalizing root operation names is part of the federation spec, it makes sense to keep the implementing services simple and fix this just once in the gateway.
1 parent 2f5f292 commit db167ad

File tree

3 files changed

+24
-9
lines changed

3 files changed

+24
-9
lines changed

packages/apollo-federation/src/composition/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from './compose';
22
export * from './composeAndValidate';
33
export * from './types';
44
export { compositionRules } from './rules';
5+
export { defaultRootOperationNameLookup } from './normalize';

packages/apollo-federation/src/composition/normalize.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@ export function normalizeTypeDefs(typeDefs: DocumentNode) {
1515
);
1616
}
1717

18+
// Map of OperationTypeNode to its respective default root operation type name
19+
export const defaultRootOperationNameLookup: {
20+
[node in OperationTypeNode]: DefaultRootOperationTypeName;
21+
} = {
22+
query: 'Query',
23+
mutation: 'Mutation',
24+
subscription: 'Subscription',
25+
};
26+
1827
export function defaultRootOperationTypes(
1928
typeDefs: DocumentNode,
2029
): DocumentNode {
21-
// Map of OperationTypeNode to its respective default root operation type name
22-
const defaultRootOperationNameLookup: {
23-
[node in OperationTypeNode]: DefaultRootOperationTypeName;
24-
} = {
25-
query: 'Query',
26-
mutation: 'Mutation',
27-
subscription: 'Subscription',
28-
};
29-
3030
// Array of default root operation names
3131
const defaultRootOperationNames = Object.values(
3232
defaultRootOperationNameLookup,

packages/apollo-gateway/src/executeQueryPlan.ts

+14
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
GraphQLFieldResolver,
1313
} from 'graphql';
1414
import { Trace, google } from 'apollo-engine-reporting-protobuf';
15+
import { defaultRootOperationNameLookup } from '@apollo/federation';
1516
import { GraphQLDataSource } from './datasources/types';
1617
import {
1718
FetchNode,
@@ -361,6 +362,19 @@ async function executeFetch<TContext>(
361362
traceParsingFailed = true;
362363
}
363364
}
365+
if (traceNode.trace) {
366+
// Federation requires the root operations in the composed schema
367+
// to have the default names (Query, Mutation, Subscription) even
368+
// if the implementing services choose different names, so we override
369+
// whatever the implementing service reported here.
370+
const rootTypeName =
371+
defaultRootOperationNameLookup[
372+
context.operationContext.operation.operation
373+
];
374+
traceNode.trace.root?.child?.forEach((child) => {
375+
child.parentType = rootTypeName;
376+
});
377+
}
364378
traceNode.traceParsingFailed = traceParsingFailed;
365379
}
366380
}

0 commit comments

Comments
 (0)