Skip to content

Commit

Permalink
[AS-252] gateway: normalize root operation types in reporting (#4100)
Browse files Browse the repository at this point in the history
  • Loading branch information
glasser authored and trevor-scheer committed May 11, 2020
1 parent 2d0cf8c commit c859219
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 19 deletions.
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

0 comments on commit c859219

Please sign in to comment.