Skip to content

gateway: Update gateway.load() to support AS2 and AS3 #819

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
merged 1 commit into from
Jun 16, 2021
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
8 changes: 3 additions & 5 deletions gateway-js/src/__tests__/integration/nockMocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,15 @@ import { getTestingSupergraphSdl } from '../../__tests__/execution-utils';
import { print } from 'graphql';
import { fixtures } from 'apollo-federation-integration-testsuite';

export const graphId = 'federated-service';
export const graphVariant = 'current';
export const graphRef = 'federated-service@current';
export const apiKey = 'service:federated-service:DD71EBbGmsuh-6suUVDwnA';
const apiKeyHash = 'dd55a79d467976346d229a7b12b673ce';

export const mockApolloConfig = {
apollo: {
key: apiKey,
keyHash: apiKeyHash,
graphId,
graphVariant,
graphRef,
},
};

Expand Down Expand Up @@ -73,7 +71,7 @@ export function mockSupergraphSdlRequest() {
return gatewayNock(mockCloudConfigUrl).post('/', {
query: SUPERGRAPH_SDL_QUERY,
variables: {
ref: `${graphId}@${graphVariant}`,
ref: graphRef,
apiKey: apiKey,
},
});
Expand Down
15 changes: 5 additions & 10 deletions gateway-js/src/__tests__/loadSupergraphSdlFromStorage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { loadSupergraphSdlFromStorage } from '../loadSupergraphSdlFromStorage';
import { getDefaultFetcher } from '../..';
import {
mockSupergraphSdlRequestSuccess,
graphId,
graphVariant,
graphRef,
apiKey,
mockCloudConfigUrl,
mockSupergraphSdlRequest,
Expand All @@ -14,8 +13,7 @@ describe('loadSupergraphSdlFromStorage', () => {
mockSupergraphSdlRequestSuccess();
const fetcher = getDefaultFetcher();
const result = await loadSupergraphSdlFromStorage({
graphId,
graphVariant,
graphRef,
apiKey,
endpoint: mockCloudConfigUrl,
fetcher,
Expand Down Expand Up @@ -308,8 +306,7 @@ describe('loadSupergraphSdlFromStorage', () => {
const fetcher = getDefaultFetcher();
await expect(
loadSupergraphSdlFromStorage({
graphId,
graphVariant,
graphRef,
apiKey,
endpoint: mockCloudConfigUrl,
fetcher,
Expand All @@ -331,8 +328,7 @@ describe('loadSupergraphSdlFromStorage', () => {
const fetcher = getDefaultFetcher();
await expect(
loadSupergraphSdlFromStorage({
graphId,
graphVariant,
graphRef,
apiKey,
endpoint: mockCloudConfigUrl,
fetcher,
Expand All @@ -346,8 +342,7 @@ describe('loadSupergraphSdlFromStorage', () => {
const fetcher = getDefaultFetcher();
await expect(
loadSupergraphSdlFromStorage({
graphId,
graphVariant,
graphRef,
apiKey,
endpoint: mockCloudConfigUrl,
fetcher,
Expand Down
53 changes: 37 additions & 16 deletions gateway-js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
GraphQLExecutionResult,
Logger,
GraphQLRequestContextExecutionDidStart,
ApolloConfig,
} from 'apollo-server-types';
import { InMemoryLRUCache } from 'apollo-server-caching';
import {
Expand Down Expand Up @@ -126,7 +125,7 @@ export const SERVICE_DEFINITION_QUERY =

type GatewayState =
| { phase: 'initialized' }
| { phase: 'failed to load'}
| { phase: 'failed to load' }
| { phase: 'loaded' }
| { phase: 'stopping'; stoppingDonePromise: Promise<void> }
| { phase: 'stopped' }
Expand All @@ -136,13 +135,28 @@ type GatewayState =
doneWaiting: () => void;
}
| { phase: 'polling'; pollingDonePromise: Promise<void> };

interface ApolloConfigFromAS3 {
key?: string;
keyHash?: string;
graphRef?: string;
}

interface ApolloConfigFromAS2Or3 {
key?: string;
keyHash?: string;
graphRef?: string;
graphId?: string;
graphVariant?: string;
}

export class ApolloGateway implements GraphQLService {
public schema?: GraphQLSchema;
private serviceMap: DataSourceMap = Object.create(null);
private config: GatewayConfig;
private logger: Logger;
private queryPlanStore: InMemoryLRUCache<QueryPlan>;
private apolloConfig?: ApolloConfig;
private apolloConfig?: ApolloConfigFromAS3;
private onSchemaChangeListeners = new Set<SchemaChangeCallback>();
private serviceDefinitions: ServiceDefinition[] = [];
private compositionMetadata?: CompositionMetadata;
Expand Down Expand Up @@ -306,7 +320,7 @@ export class ApolloGateway implements GraphQLService {
}

public async load(options?: {
apollo?: ApolloConfig;
apollo?: ApolloConfigFromAS2Or3;
engine?: GraphQLServiceEngineConfig;
}) {
if (this.state.phase !== 'initialized') {
Expand All @@ -315,13 +329,22 @@ export class ApolloGateway implements GraphQLService {
);
}
if (options?.apollo) {
this.apolloConfig = options.apollo;
const { key, keyHash, graphRef, graphId, graphVariant } = options.apollo;
this.apolloConfig = {
key,
keyHash,
graphRef:
graphRef ??
(graphId ? `${graphId}@${graphVariant ?? 'current'}` : undefined),
};
} else if (options?.engine) {
// Older version of apollo-server-core that isn't passing 'apollo' yet.
const { apiKeyHash, graphId, graphVariant } = options.engine;
this.apolloConfig = {
keyHash: options.engine.apiKeyHash,
graphId: options.engine.graphId,
graphVariant: options.engine.graphVariant || 'current',
keyHash: apiKeyHash,
graphRef: graphId
? `${graphId}@${graphVariant ?? 'current'}`
: undefined,
};
}

Expand Down Expand Up @@ -363,8 +386,8 @@ export class ApolloGateway implements GraphQLService {
const mode = isManagedConfig(this.config) ? 'managed' : 'unmanaged';
this.logger.info(
`Gateway successfully loaded schema.\n\t* Mode: ${mode}${
this.apolloConfig && this.apolloConfig.graphId
? `\n\t* Service: ${this.apolloConfig.graphId}@${this.apolloConfig.graphVariant}`
this.apolloConfig && this.apolloConfig.graphRef
? `\n\t* Service: ${this.apolloConfig.graphRef}`
: ''
}`,
);
Expand Down Expand Up @@ -861,7 +884,7 @@ export class ApolloGateway implements GraphQLService {
}

const canUseManagedConfig =
this.apolloConfig?.graphId && this.apolloConfig?.keyHash;
this.apolloConfig?.graphRef && this.apolloConfig?.keyHash;
if (!canUseManagedConfig) {
throw new Error(
'When a manual configuration is not provided, gateway requires an Apollo ' +
Expand All @@ -877,26 +900,24 @@ export class ApolloGateway implements GraphQLService {
!isPrecomposedManagedConfig(config)
) {
return getServiceDefinitionsFromStorage({
graphId: this.apolloConfig!.graphId!,
graphRef: this.apolloConfig!.graphRef!,
apiKeyHash: this.apolloConfig!.keyHash!,
graphVariant: this.apolloConfig!.graphVariant,
federationVersion: config.federationVersion || 1,
fetcher: this.fetcher,
});
}

return loadSupergraphSdlFromStorage({
graphId: this.apolloConfig!.graphId!,
graphRef: this.apolloConfig!.graphRef!,
apiKey: this.apolloConfig!.key!,
graphVariant: this.apolloConfig!.graphVariant,
endpoint: this.experimental_schemaConfigDeliveryEndpoint!,
fetcher: this.fetcher,
});
}

private maybeWarnOnConflictingConfig() {
const canUseManagedConfig =
this.apolloConfig?.graphId && this.apolloConfig?.keyHash;
this.apolloConfig?.graphRef && this.apolloConfig?.keyHash;

// This might be a bit confusing just by reading, but `!isManagedConfig` just
// means it's any of the other types of config. If it's any other config _and_
Expand Down
12 changes: 8 additions & 4 deletions gateway-js/src/legacyLoadServicesFromStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,22 @@ function fetchApolloGcs(
}

export async function getServiceDefinitionsFromStorage({
graphId,
graphRef,
apiKeyHash,
graphVariant,
federationVersion,
fetcher,
}: {
graphId: string;
graphRef: string;
apiKeyHash: string;
graphVariant: string;
federationVersion: number;
fetcher: typeof fetch;
}): Promise<ServiceDefinitionUpdate> {
// The protocol for talking to GCS requires us to split the graph ref
// into ID and variant; sigh.
const at = graphRef.indexOf('@');
const graphId = at === -1 ? graphRef : graphRef.substring(0, at);
const graphVariant = at === -1 ? 'current' : graphRef.substring(at + 1);

Comment on lines +111 to +116
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// The protocol for talking to GCS requires us to split the graph ref
// into ID and variant; sigh.
const at = graphRef.indexOf('@');
const graphId = at === -1 ? graphRef : graphRef.substring(0, at);
const graphVariant = at === -1 ? 'current' : graphRef.substring(at + 1);
// The protocol for talking to GCS requires us to split the graph ref
// into ID and variant; sigh.
const [graphId, graphVariant = "current"] = graphRef.split("@");

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's cool syntax I hadn't thought of. But if there are multiple @s it just silently drops whatever is after the second, right? Not really legal variant but still. (Super messed up that the limit arg to JS string.split isn't "stop splitting after N pieces" but "throw away all bit the first N pieces".)

// fetch the storage secret
const storageSecretUrl = getStorageSecretUrl(graphId, apiKeyHash);

Expand Down
8 changes: 3 additions & 5 deletions gateway-js/src/loadSupergraphSdlFromStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,12 @@ const { name, version } = require('../package.json');
const fetchErrorMsg = "An error occurred while fetching your schema from Apollo: ";

export async function loadSupergraphSdlFromStorage({
graphId,
graphVariant,
graphRef,
apiKey,
endpoint,
fetcher,
}: {
graphId: string;
graphVariant: string;
graphRef: string;
apiKey: string;
endpoint: string;
fetcher: typeof fetch;
Expand All @@ -56,7 +54,7 @@ export async function loadSupergraphSdlFromStorage({
body: JSON.stringify({
query: SUPERGRAPH_SDL_QUERY,
variables: {
ref: `${graphId}@${graphVariant}`,
ref: graphRef,
apiKey,
},
}),
Expand Down