Skip to content

Commit

Permalink
Merge branch 'master' into release-2.14.0
Browse files Browse the repository at this point in the history
  • Loading branch information
abernix committed May 12, 2020
2 parents 94f6c47 + 69b3177 commit da3de57
Show file tree
Hide file tree
Showing 14 changed files with 76 additions and 36 deletions.
8 changes: 8 additions & 0 deletions federation-js/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
- _Nothing yet! Stay tuned._

## 0.16.0

- No changes. This package was major versioned to maintain lockstep versioning with @apollo/gateway.

## 0.15.1

- 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

> [See complete versioning details.](https://github.com/apollographql/apollo-server/commit/e37384a49b2bf474eed0de3e9f4a1bebaeee64c7)
Expand Down
2 changes: 1 addition & 1 deletion federation-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@apollo/federation",
"version": "0.15.0",
"version": "0.16.0",
"description": "Apollo Federation Utilities",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
1 change: 1 addition & 0 deletions federation-js/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 federation-js/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
9 changes: 9 additions & 0 deletions gateway-js/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@

> 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._

## 0.16.0

- __BREAKING__: Use a content delivery network for managed configuration, fetch storage secrets and composition configuration from different domains: https://storage-secrets.api.apollographql.com and https://federation.api.apollographql.com. Please mind any firewall for outgoing traffic. [#4080](https://github.com/apollographql/apollo-server/pull/4080)

## 0.15.1

- __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
2 changes: 1 addition & 1 deletion gateway-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@apollo/gateway",
"version": "0.15.0",
"version": "0.16.0",
"description": "Apollo Gateway",
"author": "[email protected]",
"main": "dist/index.js",
Expand Down
11 changes: 8 additions & 3 deletions gateway-js/src/__tests__/__fixtures__/schemas/accounts.ts
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 gateway-js/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
8 changes: 4 additions & 4 deletions gateway-js/src/__tests__/executeQueryPlan.test.ts
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
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ it(`Errors when the secret isn't hosted on GCS`, async () => {
await expect(
gateway.load({ engine: { apiKeyHash, graphId } }),
).rejects.toThrowErrorMatchingInlineSnapshot(
`"Unable to authenticate with Apollo Graph Manager storage while fetching https://storage.googleapis.com/engine-partial-schema-prod/federated-service/storage-secret/dd55a79d467976346d229a7b12b673ce.json. Ensure that the API key is configured properly and that a federated service has been pushed. For details, see https://go.apollo.dev/g/resolve-access-denied."`,
`"Unable to authenticate with Apollo Graph Manager storage while fetching https://storage-secrets.api.apollographql.com/federated-service/storage-secret/dd55a79d467976346d229a7b12b673ce.json. Ensure that the API key is configured properly and that a federated service has been pushed. For details, see https://go.apollo.dev/g/resolve-access-denied."`,
);
});

Expand Down
24 changes: 12 additions & 12 deletions gateway-js/src/__tests__/integration/nockMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,23 @@ function gcsNock(url: Parameters<typeof nock>[0]): nock.Scope {
}

export function mockStorageSecret() {
return gcsNock('https://storage.googleapis.com:443').get(
`/engine-partial-schema-prod/${graphId}/storage-secret/${apiKeyHash}.json`,
return gcsNock('https://storage-secrets.api.apollographql.com:443').get(
`/${graphId}/storage-secret/${apiKeyHash}.json`,
);
}

export function mockStorageSecretSuccess() {
return gcsNock('https://storage.googleapis.com:443')
return gcsNock('https://storage-secrets.api.apollographql.com:443')
.get(
`/engine-partial-schema-prod/${graphId}/storage-secret/${apiKeyHash}.json`,
`/${graphId}/storage-secret/${apiKeyHash}.json`,
)
.reply(200, `"${storageSecret}"`);
}

// get composition config link, using received storage secret
export function mockCompositionConfigLink() {
return gcsNock('https://storage.googleapis.com:443').get(
`/engine-partial-schema-prod/${storageSecret}/current/v1/composition-config-link`,
return gcsNock('https://federation.api.apollographql.com:443').get(
`/${storageSecret}/current/v1/composition-config-link`,
);
}

Expand All @@ -72,8 +72,8 @@ export function mockCompositionConfigLinkSuccess() {

// get composition configs, using received composition config link
export function mockCompositionConfigs() {
return gcsNock('https://storage.googleapis.com:443').get(
`/engine-partial-schema-prod/${storageSecret}/current/v1/composition-configs/composition-config-path.json`,
return gcsNock('https://federation.api.apollographql.com:443').get(
`/${storageSecret}/current/v1/composition-configs/composition-config-path.json`,
);
}

Expand All @@ -88,8 +88,8 @@ export function mockCompositionConfigsSuccess(services: MockService[]) {

// get implementing service reference, using received composition-config
export function mockImplementingServices({ gcsDefinitionPath }: MockService) {
return gcsNock('https://storage.googleapis.com:443').get(
`/engine-partial-schema-prod/${storageSecret}/current/v1/implementing-services/${accountsService}/${gcsDefinitionPath}`,
return gcsNock('https://federation.api.apollographql.com:443').get(
`/${storageSecret}/current/v1/implementing-services/${accountsService}/${gcsDefinitionPath}`,
);
}

Expand All @@ -103,8 +103,8 @@ export function mockImplementingServicesSuccess(service: MockService) {

// get raw-partial-schema, using received composition-config
export function mockRawPartialSchema({ partialSchemaPath }: MockService) {
return gcsNock('https://storage.googleapis.com:443').get(
`/engine-partial-schema-prod/${storageSecret}/current/raw-partial-schemas/${partialSchemaPath}`,
return gcsNock('https://federation.api.apollographql.com:443').get(
`/${storageSecret}/current/raw-partial-schemas/${partialSchemaPath}`,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@ describe('getServiceDefinitionsFromRemoteEndpoint', () => {

const dataSource = new RemoteGraphQLDataSource({ url });
const serviceList = [{ name: 'test', url, dataSource }];
// Depending on the OS's resolver, the error may result in an error
// of `EAI_AGAIN` or `ENOTFOUND`. This `toThrowError` uses a Regex
// to match either case.
await expect(
getServiceDefinitionsFromRemoteEndpoint({
serviceList,
serviceSdlCache,
}),
).rejects.toThrowError(/^Couldn't load service definitions for "test" at http:\/\/host-which-better-not-resolve\/graphql: request to http:\/\/host-which-better-not-resolve\/graphql failed, reason: getaddrinfo ENOTFOUND/);
).rejects.toThrowError(/^Couldn't load service definitions for "test" at http:\/\/host-which-better-not-resolve\/graphql: request to http:\/\/host-which-better-not-resolve\/graphql failed, reason: getaddrinfo (ENOTFOUND|EAI_AGAIN)/);
});
});
14 changes: 14 additions & 0 deletions gateway-js/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
4 changes: 2 additions & 2 deletions gateway-js/src/loadServicesFromStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ const urlFromEnvOrDefault = (envKey: string, fallback: string) =>
// Generate and cache our desired operation manifest URL.
const urlPartialSchemaBase = urlFromEnvOrDefault(
envOverridePartialSchemaBaseUrl,
'https://storage.googleapis.com/engine-partial-schema-prod/',
'https://federation.api.apollographql.com/',
);

const urlStorageSecretBase: string = urlFromEnvOrDefault(
envOverrideStorageSecretBaseUrl,
'https://storage.googleapis.com/engine-partial-schema-prod/',
'https://storage-secrets.api.apollographql.com/',
);

function getStorageSecretUrl(graphId: string, apiKeyHash: string): string {
Expand Down

0 comments on commit da3de57

Please sign in to comment.