diff --git a/CHANGELOG.md b/CHANGELOG.md
index aca409d2968..621c78b74ca 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ The version headers in this history reflect the versions of Apollo Server itself
## vNEXT
+- `apollo-server-core`: For ease of testing, you can specify the node environment via `new ApolloServer({nodeEnv})` in addition to via the `NODE_ENV` environment variable. The environment variable is now only read during server startup (and in some error cases) rather than on every request. [PR #5657](https://github.com/apollographql/apollo-server/pull/5657)
- `apollo-server-koa`: The peer dependency on `koa` (added in v3.0.0) should be a `^` range dependency rather than depending on exactly one version, and it should not be automatically increased when new versions of `koa` are released. [PR #5759](https://github.com/apollographql/apollo-server/pull/5759)
- `apollo-server-fastify`: Export `ApolloServerFastifyConfig` and `FastifyContext` TypeScript types. [PR #5743](https://github.com/apollographql/apollo-server/pull/5743)
- `apollo-server-core`: Only generate the schema hash once on startup rather than twice. [PR #5757](https://github.com/apollographql/apollo-server/pull/5757)
diff --git a/docs/source/api/apollo-server.md b/docs/source/api/apollo-server.md
index 57263e90dea..a22bc638ba7 100644
--- a/docs/source/api/apollo-server.md
+++ b/docs/source/api/apollo-server.md
@@ -390,6 +390,19 @@ The default value is `true`. Set this to `false` to use mocked resolvers only fo
+
+
+
+##### `nodeEnv`
+
+`String`
+ |
+
+
+If this is set to any string value, use that value instead of the environment variable `NODE_ENV` for the features whose defaults depend on `NODE_ENV` (like the [`debug`](#introspection) and [`introspection`](#introspection) options). Note that passing the empty string here is equivalent to running with the `NODE_ENV` environment variable unset. This is primarily meant for testing the effects of the `NODE_ENV` environment variable.
+ |
+
+
diff --git a/packages/apollo-datasource-rest/src/RESTDataSource.ts b/packages/apollo-datasource-rest/src/RESTDataSource.ts
index dba8b86b86a..591464eaf9e 100644
--- a/packages/apollo-datasource-rest/src/RESTDataSource.ts
+++ b/packages/apollo-datasource-rest/src/RESTDataSource.ts
@@ -44,6 +44,8 @@ export interface CacheOptions {
export type Body = BodyInit | object;
export { Request };
+const NODE_ENV = process.env.NODE_ENV;
+
export abstract class RESTDataSource extends DataSource {
httpCache!: HTTPCache;
context!: TContext;
@@ -282,7 +284,7 @@ export abstract class RESTDataSource extends DataSource {
request: Request,
fn: () => Promise,
): Promise {
- if (process.env.NODE_ENV === 'development') {
+ if (NODE_ENV === 'development') {
// We're not using console.time because that isn't supported on Cloudflare
const startTime = Date.now();
try {
diff --git a/packages/apollo-server-core/src/ApolloServer.ts b/packages/apollo-server-core/src/ApolloServer.ts
index 8f49e045b09..1f9c420464b 100644
--- a/packages/apollo-server-core/src/ApolloServer.ts
+++ b/packages/apollo-server-core/src/ApolloServer.ts
@@ -151,7 +151,10 @@ export class ApolloServerBase<
// The constructor should be universal across all environments. All environment specific behavior should be set by adding or overriding methods
constructor(config: Config) {
if (!config) throw new Error('ApolloServer requires options.');
- this.config = config;
+ this.config = {
+ ...config,
+ nodeEnv: config.nodeEnv ?? process.env.NODE_ENV,
+ };
const {
context,
resolvers,
@@ -170,7 +173,7 @@ export class ApolloServerBase<
mockEntireSchema,
experimental_approximateDocumentStoreMiB,
...requestOptions
- } = config;
+ } = this.config;
// Setup logging facilities
if (config.logger) {
@@ -206,16 +209,7 @@ export class ApolloServerBase<
this.experimental_approximateDocumentStoreMiB =
experimental_approximateDocumentStoreMiB;
- // Allow tests to override process.env.NODE_ENV. As a bonus, this means
- // we're only reading the env var once in the constructor, which is faster
- // than reading it over and over as each read is a syscall. Note that an
- // explicit `__testing_nodeEnv__: undefined` overrides a set environment
- // variable!
- const nodeEnv =
- '__testing_nodeEnv__' in config
- ? config.__testing_nodeEnv__
- : process.env.NODE_ENV;
- const isDev = nodeEnv !== 'production';
+ const isDev = this.config.nodeEnv !== 'production';
// We handle signals if it was explicitly requested, or if we're in Node,
// not in a test, not in a serverless framework, and it wasn't explicitly
@@ -224,7 +218,9 @@ export class ApolloServerBase<
this.stopOnTerminationSignals =
typeof stopOnTerminationSignals === 'boolean'
? stopOnTerminationSignals
- : isNodeLike && nodeEnv !== 'test' && !this.serverlessFramework();
+ : isNodeLike &&
+ this.config.nodeEnv !== 'test' &&
+ !this.serverlessFramework();
// if this is local dev, introspection should turned on
// in production, we can manually turn introspection on by passing {
diff --git a/packages/apollo-server-core/src/__tests__/runHttpQuery.test.ts b/packages/apollo-server-core/src/__tests__/runHttpQuery.test.ts
index 62db5c5a853..8ddc9e2c5a7 100644
--- a/packages/apollo-server-core/src/__tests__/runHttpQuery.test.ts
+++ b/packages/apollo-server-core/src/__tests__/runHttpQuery.test.ts
@@ -29,6 +29,7 @@ describe('runHttpQuery', () => {
query: '{ testString }',
},
options: {
+ debug: false,
schema,
schemaHash: generateSchemaHash(schema),
},
diff --git a/packages/apollo-server-core/src/graphqlOptions.ts b/packages/apollo-server-core/src/graphqlOptions.ts
index 77003c661be..61453a2f96e 100644
--- a/packages/apollo-server-core/src/graphqlOptions.ts
+++ b/packages/apollo-server-core/src/graphqlOptions.ts
@@ -58,7 +58,7 @@ export interface GraphQLServerOptions<
plugins?: ApolloServerPlugin[];
documentStore?: InMemoryLRUCache;
parseOptions?: ParseOptions;
- __testing_nodeEnv__?: string | undefined;
+ nodeEnv?: string;
}
export type DataSources = {
diff --git a/packages/apollo-server-core/src/runHttpQuery.ts b/packages/apollo-server-core/src/runHttpQuery.ts
index 8555050badb..6153634140b 100644
--- a/packages/apollo-server-core/src/runHttpQuery.ts
+++ b/packages/apollo-server-core/src/runHttpQuery.ts
@@ -114,11 +114,13 @@ export function throwHttpGraphQLError(
);
}
+const NODE_ENV = process.env.NODE_ENV ?? '';
+
export async function runHttpQuery(
handlerArguments: Array,
request: HttpQueryRequest,
): Promise {
- function debugFromNodeEnv(nodeEnv: string | undefined) {
+ function debugFromNodeEnv(nodeEnv: string = NODE_ENV) {
return nodeEnv !== 'production' && nodeEnv !== 'test';
}
@@ -129,18 +131,15 @@ export async function runHttpQuery(
// The options can be generated asynchronously, so we don't have access to
// the normal options provided by the user, such as: formatError,
// debug. Therefore, we need to do some unnatural things, such
- // as use NODE_ENV to determine the debug settings
+ // as use NODE_ENV to determine the debug settings. Please note that this
+ // will not be sensitive to any runtime changes made to NODE_ENV.
return throwHttpGraphQLError(500, [e as Error], {
- debug: debugFromNodeEnv(process.env.NODE_ENV),
+ debug: debugFromNodeEnv(),
});
}
if (options.debug === undefined) {
- const nodeEnv =
- '__testing_nodeEnv__' in options
- ? options.__testing_nodeEnv__
- : process.env.NODE_ENV;
- options.debug = debugFromNodeEnv(nodeEnv);
+ options.debug = debugFromNodeEnv(options.nodeEnv);
}
// TODO: Errors thrown while resolving the context in
diff --git a/packages/apollo-server-core/src/types.ts b/packages/apollo-server-core/src/types.ts
index bb9fd052d1d..c2d73c7afe0 100644
--- a/packages/apollo-server-core/src/types.ts
+++ b/packages/apollo-server-core/src/types.ts
@@ -99,12 +99,5 @@ export interface Config extends BaseConfig {
experimental_approximateDocumentStoreMiB?: number;
stopOnTerminationSignals?: boolean;
apollo?: ApolloConfigInput;
- // Apollo Server only uses process.env.NODE_ENV to determine defaults for
- // other behavior which have other mechanisms of setting explicitly. Sometimes
- // our tests want to test the exact logic of how NODE_ENV affects defaults;
- // they can set this parameter, but there's no reason to do so other than for
- // tests. Note that an explicit `__testing_nodeEnv__: undefined` means "act as
- // if the environment variable is not set", whereas the absence of
- // `__testing_nodeEnv__` means to honor the environment variable.
- __testing_nodeEnv__?: string | undefined;
+ nodeEnv?: string;
}
diff --git a/packages/apollo-server-express/src/__tests__/ApolloServer.test.ts b/packages/apollo-server-express/src/__tests__/ApolloServer.test.ts
index 3ef1bde92f6..1f0ef8a63de 100644
--- a/packages/apollo-server-express/src/__tests__/ApolloServer.test.ts
+++ b/packages/apollo-server-express/src/__tests__/ApolloServer.test.ts
@@ -120,7 +120,7 @@ describe('apollo-server-express', () => {
const { httpServer } = await createServer({
typeDefs,
resolvers,
- __testing_nodeEnv__: undefined, // default landing page
+ nodeEnv: '', // default landing page
});
await request(httpServer)
@@ -265,7 +265,7 @@ describe('apollo-server-express', () => {
throw new AuthenticationError('valid result');
},
// Stack trace not included for NODE_ENV=test
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
});
const apolloFetch = createApolloFetch({ uri });
@@ -296,7 +296,7 @@ describe('apollo-server-express', () => {
},
},
// Stack trace not included for NODE_ENV=test
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
});
const apolloFetch = createApolloFetch({ uri });
@@ -326,7 +326,7 @@ describe('apollo-server-express', () => {
},
},
},
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
@@ -355,7 +355,7 @@ describe('apollo-server-express', () => {
},
},
},
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
diff --git a/packages/apollo-server-fastify/src/__tests__/ApolloServer.test.ts b/packages/apollo-server-fastify/src/__tests__/ApolloServer.test.ts
index 5da5d830160..390ad9d1f4c 100644
--- a/packages/apollo-server-fastify/src/__tests__/ApolloServer.test.ts
+++ b/packages/apollo-server-fastify/src/__tests__/ApolloServer.test.ts
@@ -178,7 +178,7 @@ describe('apollo-server-fastify', () => {
const { httpServer } = await createServer({
typeDefs,
resolvers,
- __testing_nodeEnv__: undefined, // default landing page
+ nodeEnv: '', // default landing page
});
await request(httpServer)
@@ -283,7 +283,7 @@ describe('apollo-server-fastify', () => {
throw new AuthenticationError('valid result');
},
// Stack trace not included for NODE_ENV=test
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
});
const apolloFetch = createApolloFetch({ uri });
@@ -314,7 +314,7 @@ describe('apollo-server-fastify', () => {
},
},
// Stack trace not included for NODE_ENV=test
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
});
const apolloFetch = createApolloFetch({ uri });
@@ -344,7 +344,7 @@ describe('apollo-server-fastify', () => {
},
},
},
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
@@ -373,7 +373,7 @@ describe('apollo-server-fastify', () => {
},
},
},
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
diff --git a/packages/apollo-server-hapi/src/__tests__/ApolloServer.test.ts b/packages/apollo-server-hapi/src/__tests__/ApolloServer.test.ts
index 1d0d1a65cd7..258aa9efb0e 100644
--- a/packages/apollo-server-hapi/src/__tests__/ApolloServer.test.ts
+++ b/packages/apollo-server-hapi/src/__tests__/ApolloServer.test.ts
@@ -116,7 +116,7 @@ describe('non-integration tests', () => {
const { httpServer } = await createServer({
typeDefs,
resolvers,
- __testing_nodeEnv__: undefined, // default landing page
+ nodeEnv: '', // default landing page
});
await request(httpServer)
@@ -288,7 +288,7 @@ describe('non-integration tests', () => {
throw new AuthenticationError('valid result');
},
// Stack trace not included for NODE_ENV=test
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
});
const apolloFetch = createApolloFetch({ uri });
@@ -319,7 +319,7 @@ describe('non-integration tests', () => {
},
},
// Stack trace not included for NODE_ENV=test
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
});
const apolloFetch = createApolloFetch({ uri });
@@ -349,7 +349,7 @@ describe('non-integration tests', () => {
},
},
},
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
@@ -378,7 +378,7 @@ describe('non-integration tests', () => {
},
},
},
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
diff --git a/packages/apollo-server-integration-testsuite/src/ApolloServer.ts b/packages/apollo-server-integration-testsuite/src/ApolloServer.ts
index 48d5b91a3f7..98efebfeae7 100644
--- a/packages/apollo-server-integration-testsuite/src/ApolloServer.ts
+++ b/packages/apollo-server-integration-testsuite/src/ApolloServer.ts
@@ -248,7 +248,7 @@ export function testApolloServer(
const { url: uri } = await createApolloServer({
schema,
stopOnTerminationSignals: false,
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
});
const apolloFetch = createApolloFetch({ uri });
@@ -262,7 +262,7 @@ export function testApolloServer(
const { url: uri } = await createApolloServer({
schema,
stopOnTerminationSignals: false,
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
@@ -281,7 +281,7 @@ export function testApolloServer(
schema,
introspection: true,
stopOnTerminationSignals: false,
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
@@ -979,7 +979,7 @@ export function testApolloServer(
],
debug: true,
stopOnTerminationSignals: false,
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
...constructorOptions,
});
@@ -1595,7 +1595,7 @@ export function testApolloServer(
typeDefs,
resolvers,
stopOnTerminationSignals: false,
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
context: () => {
throw new AuthenticationError('valid result');
},
@@ -1653,7 +1653,7 @@ export function testApolloServer(
},
},
stopOnTerminationSignals: false,
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
@@ -1683,7 +1683,7 @@ export function testApolloServer(
},
},
stopOnTerminationSignals: false,
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
@@ -1714,7 +1714,7 @@ export function testApolloServer(
},
},
stopOnTerminationSignals: false,
- __testing_nodeEnv__: 'development',
+ nodeEnv: 'development',
});
const apolloFetch = createApolloFetch({ uri });
@@ -2922,7 +2922,7 @@ export function testApolloServer(
})),
],
// dev mode, so we get the local landing page
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
};
}
diff --git a/packages/apollo-server-koa/src/__tests__/ApolloServer.test.ts b/packages/apollo-server-koa/src/__tests__/ApolloServer.test.ts
index 4bf44a2eb78..6754bbae68b 100644
--- a/packages/apollo-server-koa/src/__tests__/ApolloServer.test.ts
+++ b/packages/apollo-server-koa/src/__tests__/ApolloServer.test.ts
@@ -118,7 +118,7 @@ describe('apollo-server-koa', () => {
const { httpServer } = await createServer({
typeDefs,
resolvers,
- __testing_nodeEnv__: undefined, // default landing page
+ nodeEnv: '', // default landing page
});
await request(httpServer)
@@ -254,7 +254,7 @@ describe('apollo-server-koa', () => {
throw new AuthenticationError('valid result');
},
// Stack trace not included for NODE_ENV=test
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
});
const apolloFetch = createApolloFetch({ uri });
@@ -285,7 +285,7 @@ describe('apollo-server-koa', () => {
},
},
// Stack trace not included for NODE_ENV=test
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
});
const apolloFetch = createApolloFetch({ uri });
@@ -315,7 +315,7 @@ describe('apollo-server-koa', () => {
},
},
},
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
@@ -344,7 +344,7 @@ describe('apollo-server-koa', () => {
},
},
},
- __testing_nodeEnv__: 'production',
+ nodeEnv: 'production',
});
const apolloFetch = createApolloFetch({ uri });
diff --git a/packages/apollo-server-micro/src/__tests__/ApolloServer.test.ts b/packages/apollo-server-micro/src/__tests__/ApolloServer.test.ts
index c1bd900b0c2..e92340714d8 100644
--- a/packages/apollo-server-micro/src/__tests__/ApolloServer.test.ts
+++ b/packages/apollo-server-micro/src/__tests__/ApolloServer.test.ts
@@ -85,10 +85,7 @@ describe('apollo-server-micro', function () {
});
it('should render a landing page when a browser sends in a request', async function () {
- const { service, uri } = await createServer(
- {},
- { __testing_nodeEnv__: undefined },
- );
+ const { service, uri } = await createServer({}, { nodeEnv: '' });
const body = await rp({
uri: `${uri}/graphql`,
diff --git a/packages/apollo-server/src/__tests__/index.test.ts b/packages/apollo-server/src/__tests__/index.test.ts
index af16aad80c9..4704da429c8 100644
--- a/packages/apollo-server/src/__tests__/index.test.ts
+++ b/packages/apollo-server/src/__tests__/index.test.ts
@@ -203,7 +203,7 @@ describe('apollo-server', () => {
typeDefs,
resolvers,
stopOnTerminationSignals: false,
- __testing_nodeEnv__: undefined,
+ nodeEnv: '',
});
const { server: httpServer } = await server.listen({ port: 0 });