Skip to content

[AS-252] gateway: normalize root operation types in reporting #4100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/apollo-federation/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

> The changes noted within this `vNEXT` section have not been released yet. New PRs and commits which introduce changes should include an entry in this `vNEXT` section as part of their development. When a release is being prepared, a new header will be (manually) created below and the appropriate changes within that release will be moved into the new section.

- _Nothing yet! Stay tuned._
- Export `defaultRootOperationNameLookup` and `normalizeTypeDefs`; needed by `@apollo/gateway` to normalize root operation types when reporting to Apollo Graph Manager. [#4071](https://github.com/apollographql/apollo-server/pull/4071)

## 0.15.0

Expand Down
1 change: 1 addition & 0 deletions packages/apollo-federation/src/composition/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './compose';
export * from './composeAndValidate';
export * from './types';
export { compositionRules } from './rules';
export { defaultRootOperationNameLookup, normalizeTypeDefs } from './normalize';
18 changes: 9 additions & 9 deletions packages/apollo-federation/src/composition/normalize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ export function normalizeTypeDefs(typeDefs: DocumentNode) {
);
}

// Map of OperationTypeNode to its respective default root operation type name
export const defaultRootOperationNameLookup: {
[node in OperationTypeNode]: DefaultRootOperationTypeName;
} = {
query: 'Query',
mutation: 'Mutation',
subscription: 'Subscription',
};

export function defaultRootOperationTypes(
typeDefs: DocumentNode,
): DocumentNode {
// Map of OperationTypeNode to its respective default root operation type name
const defaultRootOperationNameLookup: {
[node in OperationTypeNode]: DefaultRootOperationTypeName;
} = {
query: 'Query',
mutation: 'Mutation',
subscription: 'Subscription',
};

// Array of default root operation names
const defaultRootOperationNames = Object.values(
defaultRootOperationNameLookup,
Expand Down
1 change: 1 addition & 0 deletions packages/apollo-gateway/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
> The changes noted within this `vNEXT` section have not been released yet. New PRs and commits which introduce changes should include an entry in this `vNEXT` section as part of their development. When a release is being prepared, a new header will be (manually) created below and the appropriate changes within that release will be moved into the new section.

- __FIX__: Correctly handle unions with nested conditions that have no `possibleTypes` [#4071](https://github.com/apollographql/apollo-server/pull/4071)
- __FIX__: Normalize root operation types when reporting to Apollo Graph Manager. Federation always uses the default names `Query`, `Mutation`, and `Subscription` for root operation types even if downstream services choose different names; now we properly normalize traces received from downstream services in the same way. [#4100](https://github.com/apollographql/apollo-server/pull/4100)

## 0.15.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ export const typeDefs = gql`
directive @stream on FIELD
directive @transform(from: String!) on FIELD

extend type Query {
schema {
query: RootQuery
mutation: Mutation
}

extend type RootQuery {
user(id: ID!): User
me: User
}
Expand Down Expand Up @@ -36,7 +41,7 @@ export const typeDefs = gql`
metadata: [UserMetadata]
}

extend type Mutation {
type Mutation {
login(username: String!, password: String!): User
}

Expand Down Expand Up @@ -80,7 +85,7 @@ const libraryUsers: { [name: string]: string[] } = {
};

export const resolvers: GraphQLResolverMap<any> = {
Query: {
RootQuery: {
user(_, args) {
return { id: args.id };
},
Expand Down
4 changes: 2 additions & 2 deletions packages/apollo-gateway/src/__tests__/buildQueryPlan.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
GraphQLSchemaValidationError,
} from 'apollo-graphql';
import gql from 'graphql-tag';
import { composeServices, buildFederatedSchema } from '@apollo/federation';
import { composeServices, buildFederatedSchema, normalizeTypeDefs } from '@apollo/federation';

import { buildQueryPlan, buildOperationContext } from '../buildQueryPlan';

Expand Down Expand Up @@ -45,7 +45,7 @@ describe('buildQueryPlan', () => {
({ schema, errors } = composeServices(
Object.entries(serviceMap).map(([serviceName, service]) => ({
name: serviceName,
typeDefs: service.sdl(),
typeDefs: normalizeTypeDefs(service.sdl()),
})),
));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import gql from 'graphql-tag';
import { GraphQLRequestContext } from 'apollo-server-types';
import { AuthenticationError } from 'apollo-server-core';
import { composeServices, buildFederatedSchema } from '@apollo/federation';
import { composeServices, buildFederatedSchema, normalizeTypeDefs } from '@apollo/federation';

import { buildQueryPlan, buildOperationContext } from '../buildQueryPlan';
import { executeQueryPlan } from '../executeQueryPlan';
Expand Down Expand Up @@ -60,7 +60,7 @@ describe('executeQueryPlan', () => {
({ schema, errors } = composeServices(
Object.entries(serviceMap).map(([serviceName, service]) => ({
name: serviceName,
typeDefs: service.sdl(),
typeDefs: normalizeTypeDefs(service.sdl()),
})),
));

Expand Down Expand Up @@ -104,7 +104,7 @@ describe('executeQueryPlan', () => {

it(`should include an error when a root-level field errors out`, async () => {
overrideResolversInService('accounts', {
Query: {
RootQuery: {
me() {
throw new AuthenticationError('Something went wrong');
},
Expand Down Expand Up @@ -151,7 +151,7 @@ describe('executeQueryPlan', () => {

it(`should still include other root-level results if one root-level field errors out`, async () => {
overrideResolversInService('accounts', {
Query: {
RootQuery: {
me() {
throw new Error('Something went wrong');
},
Expand Down
14 changes: 14 additions & 0 deletions packages/apollo-gateway/src/executeQueryPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
GraphQLFieldResolver,
} from 'graphql';
import { Trace, google } from 'apollo-engine-reporting-protobuf';
import { defaultRootOperationNameLookup } from '@apollo/federation';
import { GraphQLDataSource } from './datasources/types';
import {
FetchNode,
Expand Down Expand Up @@ -361,6 +362,19 @@ async function executeFetch<TContext>(
traceParsingFailed = true;
}
}
if (traceNode.trace) {
// Federation requires the root operations in the composed schema
// to have the default names (Query, Mutation, Subscription) even
// if the implementing services choose different names, so we override
// whatever the implementing service reported here.
const rootTypeName =
defaultRootOperationNameLookup[
context.operationContext.operation.operation
];
traceNode.trace.root?.child?.forEach((child) => {
child.parentType = rootTypeName;
});
}
traceNode.traceParsingFailed = traceParsingFailed;
}
}
Expand Down