diff --git a/CHANGELOG.md b/CHANGELOG.md index 2af3579f897..ccbbe7fac65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,10 @@ The version headers in this history reflect the versions of Apollo Server itself - [__CHANGELOG for `@apollo/federation`__](https://github.com/apollographql/apollo-server/blob/master/packages/apollo-federation/CHANGELOG.md) ### vNEXT + > 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 the appropriate changes within that release will be moved into the new section. +- `apollo-engine-reporting`: Deprecate the `ENGINE_API_KEY` environment variable in favor of its new name, `APOLLO_KEY`. Continued use of `ENGINE_API_KEY` will result in deprecation warnings and support for it will be removed in a future major version. [#3923](https://github.com/apollographql/apollo-server/pull/3923) - `apollo-engine-reporting`: Deprecated the `APOLLO_SCHEMA_TAG` environment variable in favor of its new name, `APOLLO_GRAPH_VARIANT`. Similarly, within the `engine` configuration object, the `schemaTag` property has been renamed `graphVariant`. The functionality remains otherwise unchanged, but their new names mirror the name used within Apollo Graph Manager. Continued use of the now-deprecated names will result in deprecation warnings and support will be dropped completely in the next "major" update. To avoid misconfiguration, a runtime error will be thrown if _both_ new and deprecated names are set. [PR #3855](https://github.com/apollographql/apollo-server/pull/3855) - Allow passing a `WebSocket.Server` to `ApolloServer.installSubscriptionHandlers`. [PR #2314](https://github.com/apollographql/apollo-server/pull/2314) diff --git a/package-lock.json b/package-lock.json index 4ea93fcb910..c6976be992c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6391,6 +6391,7 @@ "version": "file:packages/apollo-server-cloud-functions", "requires": { "@apollographql/graphql-playground-html": "1.6.24", + "apollo-engine-reporting": "file:packages/apollo-engine-reporting", "apollo-server-core": "file:packages/apollo-server-core", "apollo-server-env": "file:packages/apollo-server-env", "apollo-server-types": "file:packages/apollo-server-types", diff --git a/packages/apollo-engine-reporting/src/agent.ts b/packages/apollo-engine-reporting/src/agent.ts index 75a3d285711..dcac41dddfe 100644 --- a/packages/apollo-engine-reporting/src/agent.ts +++ b/packages/apollo-engine-reporting/src/agent.ts @@ -16,6 +16,8 @@ import { GraphQLRequestContext, Logger } from 'apollo-server-types'; import { InMemoryLRUCache } from 'apollo-server-caching'; import { defaultEngineReportingSignature } from 'apollo-graphql'; +let warnedOnDeprecatedApiKey = false; + export interface ClientInfo { clientName?: string; clientVersion?: string; @@ -45,7 +47,30 @@ export type GenerateClientInfo = ( requestContext: GraphQLRequestContext, ) => ClientInfo; -// AS3: Drop support for deprecated bits. +// AS3: Drop support for deprecated `ENGINE_API_KEY`. +export function getEngineApiKey( + {engine, skipWarn = false, logger= console }: + {engine: EngineReportingOptions | boolean | undefined, skipWarn?: boolean, logger?: Logger } + ) { + if (typeof engine === 'object') { + if (engine.apiKey) { + return engine.apiKey; + } + } + const legacyApiKeyFromEnv = process.env.ENGINE_API_KEY; + const apiKeyFromEnv = process.env.APOLLO_KEY; + + if(legacyApiKeyFromEnv && apiKeyFromEnv && !skipWarn) { + logger.warn(`Both ENGINE_API_KEY (deprecated) and APOLLO_KEY are set; defaulting to APOLLO_KEY.`); + } + if(legacyApiKeyFromEnv && !warnedOnDeprecatedApiKey && !skipWarn) { + logger.warn(`[deprecated] Setting the key via ENGINE_API_KEY is deprecated and will not be supported in future versions.`); + warnedOnDeprecatedApiKey = true; + } + return apiKeyFromEnv || legacyApiKeyFromEnv || '' +} + +// AS3: Drop support for deprecated `ENGINE_SCHEMA_TAG`. export function getEngineGraphVariant(engine: EngineReportingOptions | boolean | undefined, logger: Logger = console): string | undefined { if (engine === false) { return; @@ -242,9 +267,9 @@ const serviceHeaderDefaults = { // EngineReportingExtensions for each request and sends batches of trace reports // to the Engine server. export class EngineReportingAgent { - private options: EngineReportingOptions; + private readonly options: EngineReportingOptions; + private readonly apiKey: string; private logger: Logger = console; - private apiKey: string; private graphVariant: string; private reports: { [schemaHash: string]: FullTracesReport } = Object.create( null, @@ -262,12 +287,12 @@ export class EngineReportingAgent { public constructor(options: EngineReportingOptions = {}) { this.options = options; + this.apiKey = getEngineApiKey({engine: this.options, skipWarn: false, logger: this.logger}); if (options.logger) this.logger = options.logger; - this.apiKey = options.apiKey || process.env.ENGINE_API_KEY || ''; this.graphVariant = getEngineGraphVariant(options, this.logger) || ''; if (!this.apiKey) { throw new Error( - 'To use EngineReportingAgent, you must specify an API key via the apiKey option or the ENGINE_API_KEY environment variable.', + `To use EngineReportingAgent, you must specify an API key via the apiKey option or the APOLLO_KEY environment variable.`, ); } diff --git a/packages/apollo-gateway/CHANGELOG.md b/packages/apollo-gateway/CHANGELOG.md index e6f2dbfd589..bce2b5e9103 100644 --- a/packages/apollo-gateway/CHANGELOG.md +++ b/packages/apollo-gateway/CHANGELOG.md @@ -4,7 +4,8 @@ > 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 the appropriate changes within that release will be moved into the new section. -- Deprecated the `APOLLO_SCHEMA_TAG` environment variable in favor of its new name, `APOLLO_GRAPH_VARIANT`. The functionality remains otherwise identical, but the new name mirrors the name used within Apollo Graph Manager. Use of the now-deprecated name will result in a deprecation warning and support will be dropped completely in a future "major" update. To avoid misconfiguration, runtime errors will be thrown if the new and deprecated name are _both_ set. [#3855](https://github.com/apollographql/apollo-server/pull/3855) +- Deprecated the `ENGINE_API_KEY` environment variable in favor of its new name, `APOLLO_KEY`. Continued use of `ENGINE_API_KEY` will result in deprecation warnings being printed to the server console. Support for `ENGINE_API_KEY` will be removed in a future, major update. [#3923](https://github.com/apollographql/apollo-server/pull/3923) +- Deprecated the `APOLLO_SCHEMA_TAG` environment variable in favor of its new name, `APOLLO_GRAPH_VARIANT`. The functionality remains otherwise identical, but the new name mirrors the name used within Apollo Graph Manager. Use of the now-deprecated name will result in a deprecation warning being printed to the server console. Support will be removed entirely in a future, major update. To avoid misconfiguration, runtime errors will be thrown if the new and deprecated name are _both_ set. [#3855](https://github.com/apollographql/apollo-server/pull/3855) - Cache stringified representations of downstream query bodies within the query plan to address performance implications incurred by repeatedly `print`ing the same`DocumentNode`s with the `graphql` printer. This improvement is more pronounced on larger documents. [PR #4018](https://github.com/apollographql/apollo-server/pull/4018) - Add inadvertently excluded `apollo-server-errors` runtime dependency. [#3927](https://github.com/apollographql/apollo-server/pull/3927) @@ -29,6 +30,7 @@ - Implement retry logic for requests to GCS [PR #3836](https://github.com/apollographql/apollo-server/pull/3836) Note: coupled with this change is a small alteration in how the gateway polls GCS for updates in managed mode. Previously, the tick was on a specific interval. Now, every tick starts after the round of fetches to GCS completes. For more details, see the linked PR. - Gateway issues health checks to downstream services via `serviceHealthCheck` configuration option. Note: expected behavior differs between managed and unmanaged federation. See PR for new test cases and documentation. [#3930](https://github.com/apollographql/apollo-server/pull/3930) + ## 0.13.2 - __BREAKING__: The behavior and signature of `RemoteGraphQLDataSource`'s `didReceiveResponse` method has been changed. No changes are necessary _unless_ your implementation has overridden the default behavior of this method by either extending the class and overriding the method or by providing `didReceiveResponse` as a parameter to the `RemoteGraphQLDataSource`'s constructor options. Implementations which have provided their own `didReceiveResponse` using either of these methods should view the PR linked here for details on what has changed. [PR #3743](https://github.com/apollographql/apollo-server/pull/3743) diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts index 67872846dfa..f5de66b3c20 100644 --- a/packages/apollo-server-core/src/ApolloServer.ts +++ b/packages/apollo-server-core/src/ApolloServer.ts @@ -71,7 +71,7 @@ import { import { Headers } from 'apollo-server-env'; import { buildServiceDefinition } from '@apollographql/apollo-tools'; -import {getEngineGraphVariant} from "apollo-engine-reporting/dist/agent"; +import { getEngineApiKey, getEngineGraphVariant } from "apollo-engine-reporting/dist/agent"; import { Logger } from "apollo-server-types"; const NoIntrospection = (context: ValidationContext) => ({ @@ -87,20 +87,8 @@ const NoIntrospection = (context: ValidationContext) => ({ }, }); -function getEngineApiKey(engine: Config['engine']): string | undefined { - const keyFromEnv = process.env.ENGINE_API_KEY || ''; - if (engine === false) { - return; - } else if (typeof engine === 'object' && engine.apiKey) { - return engine.apiKey; - } else if (keyFromEnv) { - return keyFromEnv; - } - return; -} - -function getEngineServiceId(engine: Config['engine']): string | undefined { - const engineApiKey = getEngineApiKey(engine); +function getEngineServiceId(engine: Config['engine'], logger: Logger): string | undefined { + const engineApiKey = getEngineApiKey({engine, skipWarn: true, logger} ); if (engineApiKey) { return engineApiKey.split(':', 2)[1]; } @@ -330,8 +318,8 @@ export class ApolloServerBase { // service ID from the API key for plugins which only needs service ID. // The truthiness of this value can also be used in other forks of logic // related to Engine, as is the case with EngineReportingAgent just below. - this.engineServiceId = getEngineServiceId(engine); - const apiKey = getEngineApiKey(engine); + this.engineServiceId = getEngineServiceId(engine, this.logger); + const apiKey = getEngineApiKey({engine, skipWarn: true, logger: this.logger}); if (apiKey) { this.engineApiKeyHash = createSHA('sha512') .update(apiKey) diff --git a/packages/apollo-server-core/src/__tests__/ApolloServerBase.test.ts b/packages/apollo-server-core/src/__tests__/ApolloServerBase.test.ts index fc6440092cc..52013e02fe6 100644 --- a/packages/apollo-server-core/src/__tests__/ApolloServerBase.test.ts +++ b/packages/apollo-server-core/src/__tests__/ApolloServerBase.test.ts @@ -94,3 +94,50 @@ describe('ApolloServerBase construction', () => { ); }); }); + +describe('environment variables', () => { + const OLD_ENV = process.env; + + beforeEach(() => { + jest.resetModules(); + process.env = { ...OLD_ENV }; + delete process.env.ENGINE_API_KEY; + delete process.env.APOLLO_KEY; + }); + + afterEach(() => { + process.env = OLD_ENV; + }); + + it('constructs a reporting agent with the ENGINE_API_KEY (deprecated) environment variable and warns', async () => { + // set the variables + process.env.ENGINE_API_KEY = 'just:fake:stuff'; + const spyConsoleWarn = jest.spyOn(console, 'warn').mockImplementation(); + + const server = new ApolloServerBase({ + typeDefs, + resolvers + }); + + await server.stop(); + expect(spyConsoleWarn).toHaveBeenCalledTimes(1); + spyConsoleWarn.mockReset(); + }); + + it('warns with both the legacy env var and new env var set', async () => { + // set the variables + process.env.ENGINE_API_KEY = 'just:fake:stuff'; + process.env.APOLLO_KEY = 'also:fake:stuff'; + const spyConsoleWarn = jest.spyOn(console, 'warn').mockImplementation(); + + const server = new ApolloServerBase({ + typeDefs, + resolvers + }); + + await server.stop(); + // Once for deprecation, once for double-set + expect(spyConsoleWarn).toHaveBeenCalledTimes(2); + spyConsoleWarn.mockReset(); + }); +});