Skip to content

Commit

Permalink
Initial update of types, introduce deprecation warnings and prelim TODOs
Browse files Browse the repository at this point in the history
  • Loading branch information
trevor-scheer committed Nov 25, 2021
1 parent 6fdc38b commit 6e7beeb
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 23 deletions.
60 changes: 57 additions & 3 deletions gateway-js/src/__tests__/integration/configuration.test.ts
Expand Up @@ -11,6 +11,7 @@ import {
} from './nockMocks';
import { getTestingSupergraphSdl } from '../execution-utils';
import { MockService } from './networkRequests.test';
import { fixtures } from 'apollo-federation-integration-testsuite';

let logger: Logger;

Expand Down Expand Up @@ -310,11 +311,64 @@ describe('gateway config / env behavior', () => {
schemaConfigDeliveryEndpoint: 'code-config',
});

expect(gateway['schemaConfigDeliveryEndpoint']).toEqual(
'code-config',
);
expect(gateway['schemaConfigDeliveryEndpoint']).toEqual('code-config');

gateway = null;
});
});
});

describe('deprecation warnings', () => {
it('warns with `experimental_updateSupergraphSdl` option set', async () => {
new ApolloGateway({
async experimental_updateSupergraphSdl() {
return {
id: 'supergraph',
supergraphSdl: getTestingSupergraphSdl(),
};
},
logger,
});

expect(logger.warn).toHaveBeenCalledWith(
'The `experimental_updateSupergraphSdl` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the function form of the `supergraphSdl` configuration option.',
);
});

it('warns with `experimental_updateServiceDefinitions` option set', async () => {
new ApolloGateway({
async experimental_updateServiceDefinitions() {
return {
isNewSchema: false,
};
},
logger,
});

expect(logger.warn).toHaveBeenCalledWith(
'The `experimental_updateServiceDefinitions` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the function form of the `supergraphSdl` configuration option.',
);
});

it('warns with `serviceList` option set', async () => {
new ApolloGateway({
serviceList: [{ name: 'accounts', url: 'http://localhost:4001' }],
logger,
});

expect(logger.warn).toHaveBeenCalledWith(
'The `serviceList` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the function form of the `supergraphSdl` configuration option.',
);
});

it('warns with `localServiceList` option set', async () => {
new ApolloGateway({
localServiceList: fixtures,
logger,
});

expect(logger.warn).toHaveBeenCalledWith(
'The `localServiceList` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the function form of the `supergraphSdl` configuration option.',
);
});
});
75 changes: 56 additions & 19 deletions gateway-js/src/config.ts
@@ -1,8 +1,11 @@
import { GraphQLError, GraphQLSchema } from "graphql";
import { HeadersInit } from "node-fetch";
import { GraphQLError, GraphQLSchema } from 'graphql';
import { HeadersInit } from 'node-fetch';
import { fetch } from 'apollo-server-env';
import { GraphQLRequestContextExecutionDidStart, Logger } from "apollo-server-types";
import { ServiceDefinition } from "@apollo/federation";
import {
GraphQLRequestContextExecutionDidStart,
Logger,
} from 'apollo-server-types';
import { ServiceDefinition } from '@apollo/federation';
import { GraphQLDataSource } from './datasources/types';
import { QueryPlan } from '@apollo/query-planner';
import { OperationContext } from './operationContext';
Expand Down Expand Up @@ -80,7 +83,9 @@ export interface SupergraphSdlUpdate {
supergraphSdl: string;
}

export function isSupergraphSdlUpdate(update: CompositionUpdate): update is SupergraphSdlUpdate {
export function isSupergraphSdlUpdate(
update: CompositionUpdate,
): update is SupergraphSdlUpdate {
return 'supergraphSdl' in update;
}

Expand Down Expand Up @@ -128,11 +133,16 @@ interface GatewayConfigBase {
serviceHealthCheck?: boolean;
}

// TODO(trevor:removeServiceList)
export interface RemoteGatewayConfig extends GatewayConfigBase {
// @deprecated: use `supergraphSdl` in its function form instead
serviceList: ServiceEndpointDefinition[];
// @deprecated: use `supergraphSdl` in its function form instead
introspectionHeaders?:
| HeadersInit
| ((service: ServiceEndpointDefinition) => Promise<HeadersInit> | HeadersInit);
| ((
service: ServiceEndpointDefinition,
) => Promise<HeadersInit> | HeadersInit);
}

export interface ManagedGatewayConfig extends GatewayConfigBase {
Expand All @@ -143,45 +153,69 @@ export interface ManagedGatewayConfig extends GatewayConfigBase {
schemaConfigDeliveryEndpoint?: string;
}

// TODO(trevor:removeServiceList): migrate users to `supergraphSdl` function option
interface ManuallyManagedServiceDefsGatewayConfig extends GatewayConfigBase {
// @deprecated: use `supergraphSdl` in its function form instead
experimental_updateServiceDefinitions: Experimental_UpdateServiceDefinitions;
}

// TODO(trevor:removeServiceList): migrate users to `supergraphSdl` function option
interface ExperimentalManuallyManagedSupergraphSdlGatewayConfig
extends GatewayConfigBase {
// @deprecated: use `supergraphSdl` in its function form instead
experimental_updateSupergraphSdl: Experimental_UpdateSupergraphSdl;
}

interface ManuallyManagedSupergraphSdlGatewayConfig extends GatewayConfigBase {
experimental_updateSupergraphSdl: Experimental_UpdateSupergraphSdl
supergraphSdl: (
update: (updatedSupergraphSdl: string) => void,
) => Promise<string | { supergraphSdl: string; cleanup: () => void }>;
}

type ManuallyManagedGatewayConfig =
| ManuallyManagedServiceDefsGatewayConfig
| ExperimentalManuallyManagedSupergraphSdlGatewayConfig
| ManuallyManagedSupergraphSdlGatewayConfig;

// TODO(trevor:removeServiceList)
interface LocalGatewayConfig extends GatewayConfigBase {
// @deprecated: use `supergraphSdl` in its function form instead
localServiceList: ServiceDefinition[];
}

interface SupergraphSdlGatewayConfig extends GatewayConfigBase {
interface StaticSupergraphSdlGatewayConfig extends GatewayConfigBase {
supergraphSdl: string;
}

export type StaticGatewayConfig = LocalGatewayConfig | SupergraphSdlGatewayConfig;
export type StaticGatewayConfig =
| LocalGatewayConfig
| StaticSupergraphSdlGatewayConfig;

type DynamicGatewayConfig =
| ManagedGatewayConfig
| RemoteGatewayConfig
| ManuallyManagedGatewayConfig;
| ManagedGatewayConfig
| RemoteGatewayConfig
| ManuallyManagedGatewayConfig;

export type GatewayConfig = StaticGatewayConfig | DynamicGatewayConfig;

export function isLocalConfig(config: GatewayConfig): config is LocalGatewayConfig {
// TODO(trevor:removeServiceList)
export function isLocalConfig(
config: GatewayConfig,
): config is LocalGatewayConfig {
return 'localServiceList' in config;
}

export function isRemoteConfig(config: GatewayConfig): config is RemoteGatewayConfig {
// TODO(trevor:removeServiceList)
export function isRemoteConfig(
config: GatewayConfig,
): config is RemoteGatewayConfig {
return 'serviceList' in config;
}

export function isSupergraphSdlConfig(config: GatewayConfig): config is SupergraphSdlGatewayConfig {
return 'supergraphSdl' in config;
export function isStaticSupergraphSdlConfig(
config: GatewayConfig,
): config is StaticSupergraphSdlGatewayConfig {
return 'supergraphSdl' in config && typeof config.supergraphSdl === 'string';
}

// A manually managed config means the user has provided a function which
Expand All @@ -190,6 +224,7 @@ export function isManuallyManagedConfig(
config: GatewayConfig,
): config is ManuallyManagedGatewayConfig {
return (
('supergraphSdl' in config && typeof config.supergraphSdl === 'function') ||
'experimental_updateServiceDefinitions' in config ||
'experimental_updateSupergraphSdl' in config
);
Expand All @@ -203,14 +238,16 @@ export function isManagedConfig(
'schemaConfigDeliveryEndpoint' in config ||
(!isRemoteConfig(config) &&
!isLocalConfig(config) &&
!isSupergraphSdlConfig(config) &&
!isStaticSupergraphSdlConfig(config) &&
!isManuallyManagedConfig(config))
);
}

// A static config is one which loads synchronously on start and never updates
export function isStaticConfig(config: GatewayConfig): config is StaticGatewayConfig {
return isLocalConfig(config) || isSupergraphSdlConfig(config);
export function isStaticConfig(
config: GatewayConfig,
): config is StaticGatewayConfig {
return isLocalConfig(config) || isStaticSupergraphSdlConfig(config);
}

// A dynamic config is one which loads asynchronously and (can) update via polling
Expand Down
40 changes: 39 additions & 1 deletion gateway-js/src/index.ts
Expand Up @@ -31,7 +31,10 @@ import {
} from './executeQueryPlan';

import { getServiceDefinitionsFromRemoteEndpoint } from './loadServicesFromRemoteEndpoint';
import { GraphQLDataSource, GraphQLDataSourceRequestKind } from './datasources/types';
import {
GraphQLDataSource,
GraphQLDataSourceRequestKind,
} from './datasources/types';
import { RemoteGraphQLDataSource } from './datasources/RemoteGraphQLDataSource';
import { getVariableValues } from 'graphql/execution/values';
import fetcher from 'make-fetch-happen';
Expand Down Expand Up @@ -256,6 +259,7 @@ export class ApolloGateway implements GraphQLService {
this.updateServiceDefinitions = this.loadServiceDefinitions;
}

this.issueDeprecationWarningsIfApplicable();
if (isDynamicConfig(this.config)) {
this.issueDynamicWarningsIfApplicable();
}
Expand Down Expand Up @@ -312,6 +316,7 @@ export class ApolloGateway implements GraphQLService {
}

// Warn against using the pollInterval and a serviceList simultaneously
// TODO(trevor:removeServiceList)
if (this.config.experimental_pollInterval && isRemoteConfig(this.config)) {
this.logger.warn(
'Polling running services is dangerous and not recommended in production. ' +
Expand All @@ -334,6 +339,36 @@ export class ApolloGateway implements GraphQLService {
}
}

private issueDeprecationWarningsIfApplicable() {
// TODO(trevor:removeServiceList)
if ('experimental_updateSupergraphSdl' in this.config) {
this.logger.warn(
'The `experimental_updateSupergraphSdl` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the function form of the `supergraphSdl` configuration option.',
);
}

// TODO(trevor:removeServiceList)
if ('experimental_updateServiceDefinitions' in this.config) {
this.logger.warn(
'The `experimental_updateServiceDefinitions` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the function form of the `supergraphSdl` configuration option.',
);
}

// TODO(trevor:removeServiceList)
if ('serviceList' in this.config) {
this.logger.warn(
'The `serviceList` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the function form of the `supergraphSdl` configuration option.',
);
}

// TODO(trevor:removeServiceList)
if ('localServiceList' in this.config) {
this.logger.warn(
'The `localServiceList` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the function form of the `supergraphSdl` configuration option.',
);
}
}

public async load(options?: {
apollo?: ApolloConfigFromAS2Or3;
engine?: GraphQLServiceEngineConfig;
Expand Down Expand Up @@ -807,6 +842,8 @@ export class ApolloGateway implements GraphQLService {
};
}

// TODO(trevor:removeServiceList): gateway shouldn't be responsible for polling
// in the future.
// This function waits an appropriate amount, updates composition, and calls itself
// again. Note that it is an async function whose Promise is not actually awaited;
// it should never throw itself other than due to a bug in its state machine.
Expand Down Expand Up @@ -928,6 +965,7 @@ export class ApolloGateway implements GraphQLService {
protected async loadServiceDefinitions(
config: RemoteGatewayConfig | ManagedGatewayConfig,
): Promise<CompositionUpdate> {
// TODO(trevor:removeServiceList)
if (isRemoteConfig(config)) {
const serviceList = config.serviceList.map((serviceDefinition) => ({
...serviceDefinition,
Expand Down

0 comments on commit 6e7beeb

Please sign in to comment.