From c6d18e86779b2eb25de5fbad31838cffd1a08087 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Thu, 14 Jul 2022 15:55:46 -0700
Subject: [PATCH 01/19] migration: start of an editing pass
---
docs/source/migration.mdx | 62 +++++++++++++++++++++++++--------------
1 file changed, 40 insertions(+), 22 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index 598ef849b69..f76a373f4ef 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -21,9 +21,9 @@ During Apollo Server 4's alpha, we are actively looking to gather feedback and [
## Bumped dependencies
### Node.js
-Apollo Server 4 supports Node.js 14 and later. This includes all [LTS and Current versions at the time of release](https://nodejs.org/en/about/releases/).
+Apollo Server 4 supports Node.js 14 and later. (Apollo Server 3 supports Node.js 12.) This includes all [LTS and Current versions at the time of release](https://nodejs.org/en/about/releases/).
-If you're using an older version of Node.js, upgrade your runtime before upgrading to Apollo Server 4.
+If you're using Node.js 12, upgrade your runtime before upgrading to Apollo Server 4.
### `graphql`
@@ -33,7 +33,9 @@ If you're using an older version of `graphql`, upgrade it to a supported version
## Removed integrations
-Apollo Server 3 provides built-in framework integrations with the intent of making Apollo Server approachable for all developers regardless of their framework of choice. Apollo Server 4 removes these built-in integrations, enabling developers to build and maintain their own integrations in the frameworks they know best.
+Apollo Server 3 ships with a fixed set of integrations with a variety of web frameworks and serverless environments, but does not provided a supported mechanism for integrating with additional frameworks. In Apollo Server 3, changes to framework integrations could only be released with lockstep versioning with Apollo Server itself, which has made it challenging to support multiple major versions of frameworks or make other integration-specific changes.
+
+Apollo Server 4 takes a different approach. The Apollo Server core team no longer maintains most of these integrations. Instead, Apollo Server now has a simple stable web framework integration API (including explicit support for serverless framework life cycles). The core `@apollo/server` package contains an Express 4 integration (similar to AS3's `apollo-server-express` package) and a standalone server (similar to AS3's `apollo-server` package). All other integrations can be maintained by the broader open source community, allowing users of other web frameworks to make the best choices for their framework's integrations rather than expecting the core team to be intimately familiar with the best practices of a dozen different projects.
For those migrating from Apollo Server 3 to Apollo Server 4, use the below flowchart to see your migration path:
@@ -53,6 +55,8 @@ If you are using any other Apollo Server 3 framework integration package, you ca
Apollo Server 4 also removes the built-in dependency on the `cors` and `body-parser` libraries (excluding the `startStandaloneServer` function).
+TODO: show exact changes to use expressMiddleware and startStandaloneServer
+
### Wrapping of framework-specific libraries
Apollo Server 3 is distributed as a [collection of different packages](/apollo-server/integrations/middleware) for different environments and web frameworks.
@@ -77,9 +81,11 @@ Apollo Server 4 removes the below integration packages:
### `body-parser` & `cors`
-Apollo Server 4 no longer provides built-in support for the [`cors`](https://github.com/expressjs/cors) or [`body-parser`](https://www.npmjs.com/package/body-parser) libraries (excluding the [`startStandaloneServer`](#startstandaloneserver) function).
+In Apollo Server 3, each web framework integration was responsible for three things: applying CORS configuration, parsing the request message's body as JSON, and processing the JSON body as a GraphQL operation. Typically, the integration used CORS and body-parsing middleware from the framework (such as the [`cors`](https://github.com/expressjs/cors) or [`body-parser`](https://www.npmjs.com/package/body-parser) libraries for Express) to implement the first two steps, taking `cors` and `bodyParserConfig` options which were directly passed through to the underlying libraries. The types of these arguments differed across web frameworks, and some integrations didn't support them at all (eg, serverless integrations where body parsing is built into the infrastructure).
-If you want to use either `cors` or `body-parser`, you can manually add both libraries to your framework-specific middleware.
+Apollo Server 4's framework integrations are now only responsible for the third step. Users are expected to use their framework's CORS and body-parsing tools directly just like with any other JSON-based API server. When migrating from a package such as `apollo-server-express` to a function such as `expressMiddleware`, you should now set up CORS and body parsing yourself.
+
+TODO: Rewrite example as before and after (or just refer to the main example)
Below is an example of setting up `cors` and `body-parser` using the [`expressMiddleware`](#expressmiddleware) function:
@@ -117,13 +123,13 @@ console.log(`π Server ready at http://localhost:4000`);
-Apollo Server 4's new [`startStandaloneServer`](#apolloserverstandalone-and-startstandaloneserver) function (e.g., the replacement for the batteries-included `apollo-server` package) includes both the `body-parser` and `cors` packages under the hood, but neither package is configurable.
+Apollo Server 4's new [`startStandaloneServer`](#apolloserverstandalone-and-startstandaloneserver) function (e.g., the replacement for the batteries-included `apollo-server` package) does not require you to manually set up CORS or body parsing, but does not provide a mechanism for configuring these features.
### Connect
-[Connect](https://github.com/senchalabs/connect) is a predecessor of Express, supported by Apollo Server 3.
+[Connect](https://github.com/senchalabs/connect) is a predecessor of Express. In Apollo Server 3, the `apollo-server-express` package supported Connect in addition to Express.
-Apollo Server 4 no longer supports Connect out of the box. An interested developer could [build a Connect-specific middleware](/integrations/building-integrations) using the Apollo Server 4 API. A PR to this migration guide is welcome if someone does this!
+In Apollo Server 4, `expressMiddleware` no longer supports Connect. An interested developer could [build a Connect-specific middleware](/integrations/building-integrations) using the Apollo Server 4 API. A PR to this migration guide is welcome if someone does this!
## Removed constructor options
@@ -131,9 +137,11 @@ The following `ApolloServer` constructor options have been removed in favor of o
### `dataSources`
-In Apollo Server 3, the top-level [`dataSources` constructor option](/apollo-server/data/data-sources#adding-data-sources-to-apollo-server) enables you to provide `DataSource` subclasses to your resolvers via the [`context`](/apollo-server/data/resolvers/#the-context-argument) object.
+In Apollo Server 3, the top-level [`dataSources` constructor option](/apollo-server/data/data-sources#adding-data-sources-to-apollo-server) essentially added a post-processing step to your app's context function which created `DataSource` subclasses and added them to a `dataSources` field on your [`context`](/apollo-server/data/resolvers/#the-context-argument) object. This meant that the type returned by your `context` function and the context type received by resolvers and plugins were actually different. This also obfuscated the fact that the `DataSource` objects were created once per request like the rest of the context object.
+
+In Apollo Server 4, we have removed the `dataSources` constructor option. You can treat `DataSources` like any other part of your `context` object.
-In Apollo Server 4, we remove the `dataSources` constructor option to provide a more transparent way of adding data sources directly to the `context` object:
+TODO: rewrite as before and after (and fully review)
@@ -237,6 +245,8 @@ In the above example, we create a `DogsDataSource` class and then instantiate a
Expand the panel below to see another example of setting up a data source with the `RESTDataSource` class:
+TODO: fully review example
+
@@ -351,14 +361,14 @@ console.log(`Server ready at ${url}`);
### `modules`
-In Apollo Server 3, there are [several ways](https://github.com/apollographql/apollo-server/issues/6062) to provide your `ApolloServer` instance with a schema. One of these ways is using the `modules` constructor option, which uses the `buildServiceDefinition` function under the hood to specify a schema using an array of `typeDefs` and `resolvers` objects.
+In Apollo Server 3, there are [several ways](https://github.com/apollographql/apollo-server/issues/6062) to provide your `ApolloServer` instance with a schema. One of these ways is to provide `typeDefs` and `resolvers` options (each of which can optionally be an array). Another way is to use the `modules` option with an array of objects, each of which have `typeDefs` and `resolvers` keys. Surprisingly, these two options used entirely different implementations of "create a schema from `typeDefs` and `resolvers`" under the hood.
To simplify its API, Apollo Server 4 removes the `modules` constructor option. You can replace any previous usage of `modules` with the following syntax:
```js
new ApolloServer({
- typeDefs: modules.map({ typeDefs } => typeDefs,
- resolvers: modules.map({ resolvers } => resolvers,
+ typeDefs: modules.map({ typeDefs } => typeDefs),
+ resolvers: modules.map({ resolvers } => resolvers),
})
```
@@ -373,10 +383,12 @@ const server = new ApolloServer({
});
```
-Under the hood, Apollo Server 3's mocking functionality is provided via an older version of the [`@graphql-tools/mocks`](https://www.npmjs.com/package/@graphql-tools/mock) library.
+Under the hood, Apollo Server 3's mocking functionality is provided via an outdated version of the [`@graphql-tools/mocks`](https://www.npmjs.com/package/@graphql-tools/mock) library.
Apollo Server 4 removes both the `mocks` and `mockEntireSchema` constructor options. You can directly incorporate the `@graphql-tools/mock` package into your app, enabling you to get the most up-to-date mocking features. For more details on configuring mocks, see the [`@graphql-tools/mocks` docs](https://www.graphql-tools.com/docs/mocking).
+TODO: show as before/after, including being clear that mockEntireSchema is the opposite of preserveResolvers
+
```ts {5-10}
import { addMocksToSchema } from '@graphql-tools/mock';
import { makeExecutableSchema } from '@graphql-tools/schema';
@@ -412,19 +424,26 @@ Every GraphQL server supports a trivial query that requests the [`__typename`](/
https://your.server/?query=%7B__typename%7D
```
+If you really want to have a health check in your HTTP server that is unrelated to the actual health of the GraphQL execution engine (like Apollo Server 3's health check feature), you can implement that in your web framework by just adding a GET handler that always succeeds.
+
### Path parsing
-Apollo Server 4 removes support for URI path parsing (i.e., removing Apollo Server 3's previous default `/graphql` path ). If you'd like to mount your GraphQL server at a specified URL, you can do so using your framework's specific middleware.
+
+In Apollo Server 3, several web framework integrations allowed you to "mount" them at a particular URL path and then use the `path` option (which defaults to `/graphql`) to specify that they should actually only process requests at a deeper path.
+
+In Apollo Server 4, web framework integrations such as `expressMiddleware` expect that they will be mounted at the appropriate path in the first place using the web framework's routing features. If you used an integration such as `apollo-server-express` and did not configure `path` in AS3, then to maintain the same behavior you should explicitly mount your middleware at `/graphql`. (Note that the batteries-included `apollo-server` package in AS3 (replaced by `startStandaloneServer` in AS4) served at all URLs instead of having the default of `/graphql`.)
### `__resolveObject`
-Apollo Server 4 removes the dependency on `@apollographql/apollo-tooling`, additionally removing the `__resolveObject` pseudo-resolver. The `__resolveObject` function was a predecessor to
-the [`__resolveReference`](/federation/api/apollo-subgraph/#__resolvereference) method.
+Apollo Server 4 removes the dependency on `@apollographql/apollo-tooling`, additionally removing the `__resolveObject` pseudo-resolver. The `__resolveObject` function was an undocumented predecessor to
+the [`__resolveReference`](/federation/api/apollo-subgraph/#__resolvereference) method. While we believe `__resolveObject` is a useful feature, it would work better if implemented directly in `graphql-js` rather than in Apollo Server.
### `formatResponse` hook
In Apollo Server 3, the `formatResponse` hook enables you to transform the structure of GraphQL response objects before they're sent to a client.
Apollo Server 4 removes the `formatResponse` hook. We instead recommend using the `willSendResponse` plugin to do the same thing:
+TODO: write as before and after
+
```ts
const apolloServerInstance = new ApolloServer({
typeDefs,
@@ -447,15 +466,14 @@ const apolloServerInstance = new ApolloServer({
### Support for older gateway versions
+TODO: double check this
+
Apollo Server 4 drops support for [`@apollo/gateway` versions](/federation/api/apollo-gateway/) below v0.35.0.
-### Removed mocking
+### Fields from `GraphQLRequestContext` and `GraphQLServerContext`
-`mocks` and `mockEntireSchema` constructor options removed. These were a thin
-layer around a subset of the functionality of a hard-coded version of
-`@graphql-tools/mocks`, which can be used directly (TODO: show migration).
+TODO: this is where glasser got to on Jul 14
-### Fields from `GraphQLRequestContext` and `GraphQLServerContext`
In Apollo Server 4, the `debug` and `schemaHash` fields are no longer available on `GraphQLRequestContext`. Note that `GraphQLRequestContext` always returns the `response` and `http` fields.
The `schemaHash` field was an unstable hash of the introspection JSON of a schema, created for the `apollo-server-plugin-operation-registry` package. Note that the `schemaHash` field is different from the hash of the schema SDL, which schema reporting still uses.
From f0d19a8c195019a80d2be53feb7b046e4b9b8d30 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Fri, 15 Jul 2022 16:52:56 -0700
Subject: [PATCH 02/19] More progress on an editing pass
---
docs/source/migration.mdx | 527 +++++++++++++++++++-------------------
1 file changed, 270 insertions(+), 257 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index f76a373f4ef..8b77e401bc3 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -18,6 +18,136 @@ During Apollo Server 4's alpha, we are actively looking to gather feedback and [
> For a list of all breaking changes, see the [changelog](https://github.com/apollographql/apollo-server/blob/main/CHANGELOG.md).
+## Basic migration examples
+
+(TODO: better name for this section.)
+
+This migration guide describes everything that has changed in Apollo Server 4 in detail. But first, here's a high-level example of how using Apollo Server changes in the most common cases.
+
+### Migrating from `apollo-server` to `startStandaloneServer`
+
+If you used the batteries-included `apollo-server` package in Apollo Server 3, you'll want to use the `startStandaloneServer` function in Apollo Server 4. Call `startStandaloneServer(server)` instead of `server.listen()`. Note that you cannot configure CORS settings with `startStandaloneServer`; if you want to change CORS settings from the default, use `expressMiddleware` instead.
+
+
+
+```ts title="apollo-server-3-standalone.ts"
+// npm install apollo-server graphql
+import { ApolloServer } from 'apollo-server';
+import { typeDefs, resolvers } from './schema';
+
+interface MyContext {
+ token?: String;
+}
+
+async function startApolloServer() {
+ const server = new ApolloServer({
+ typeDefs,
+ resolvers,
+ context: async ({ req }) => ({ token: req.headers.token }),
+ });
+ const { url } = await server.listen(4444);
+ console.log(`π Server ready at ${url}`);
+}
+```
+
+
+
+
+
+```ts title="apollo-server-4-standalone.ts"
+// npm install @apollo/server graphql
+import { ApolloServer } from '@apollo/server';
+import { startStandaloneServer } from '@apollo/server/standalone';
+import { typeDefs, resolvers } from './schema';
+
+interface MyContext {
+ token?: String;
+}
+
+async function startApolloServer() {
+ const server = new ApolloServer({ typeDefs, resolvers });
+ const { url } = await startStandaloneServer(server, {
+ context: async ({ req }) => ({ token: req.headers.token }),
+ listen: { port: 4444 },
+ });
+ console.log(`π Server ready at ${url}`);
+}
+```
+
+
+
+
+### Migrating from `apollo-server-express` to `expressMiddleware`
+
+If you used the `apollo-server-express` package in Apollo Server 3, you'll want to use the `expressMiddleware` function in Apollo Server 4 instead of the `applyMiddleware` method. Note that by default, `apollo-server-express` in AS3 would only actually respond to operations on `/graphql`, so we explicitly mount `expressMiddleware` at that path in AS4.
+
+
+
+```ts title="apollo-server-3.ts"
+// npm install apollo-server-express apollo-server-core express graphql
+import { ApolloServer } from 'apollo-server-express';
+import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core';
+import express from 'express';
+import http from 'http';
+import { typeDefs, resolvers } from './schema';
+
+interface MyContext {
+ token?: String;
+}
+
+async function startApolloServer() {
+ const app = express();
+ const httpServer = http.createServer(app);
+ const server = new ApolloServer({
+ typeDefs,
+ resolvers,
+ context: async ({ req }) => ({ token: req.headers.token }),
+ plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
+ });
+ await server.start();
+ server.applyMiddleware({ app });
+ await new Promise(resolve => httpServer.listen({ port: 4000 }, resolve));
+ console.log(`π Server ready at http://localhost:4000${server.graphqlPath}`);
+}
+```
+
+
+
+
+
+```ts title="apollo-server-4.ts"
+// npm install @apollo/server express graphql
+import { ApolloServer } from '@apollo/server';
+import { expressMiddleware } from '@apollo/server/express4';
+import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
+import express from 'express';
+import http from 'http';
+import { typeDefs, resolvers } from './schema';
+
+interface MyContext {
+ token?: String;
+}
+
+async function startApolloServer() {
+ const app = express();
+ const httpServer = http.createServer(app);
+ const server = new ApolloServer({
+ typeDefs,
+ resolvers,
+ plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
+ });
+ await server.start();
+ app.use('/graphql', expressMiddleware(server, {
+ context: async ({ req }) => ({ token: req.headers.token }),
+ }));
+ await new Promise(resolve => httpServer.listen({ port: 4000 }, resolve));
+ console.log(`π Server ready at http://localhost:4000/graphql`);
+}
+```
+
+
+
+
## Bumped dependencies
### Node.js
@@ -470,33 +600,41 @@ TODO: double check this
Apollo Server 4 drops support for [`@apollo/gateway` versions](/federation/api/apollo-gateway/) below v0.35.0.
-### Fields from `GraphQLRequestContext` and `GraphQLServerContext`
+### Fields on `GraphQLRequestContext`
+
+Most plugin API hooks take a `GraphQLRequestContext` object as their first argument. There are several changes to this object.
+
+The `context` field has been renamed to `contextValue`, for consistency with the `graphql-js` API and to differentiate from the `context` option to integration functions, which is a *function* returning a context value.
+
+The `logger` and `cache` fields have been removed. These fields are now available as public readonly fields on the `ApolloServer` object, and `GraphQLRequestContext` now provides the `ApolloServer` object in a new field `server`, so `requestContext.logger` and `requestContext.cache` can be replaced with `requestContext.server.logger` and `requestContext.server.cache` respectively.
-TODO: this is where glasser got to on Jul 14
+The `schemaHash` field has been removed. This field was a not particularly stable hash of a JSON encoding of the result of running the GraphQL introspection query against the schema. It was not guaranteed to change when the schema changed (eg, it is not affected by changes to schema directive applications). If you need a hash of the schema, you can hash the output of applying the `graphql-js` `printSchema` function to the `schema` field (perhaps with some sort of memoization).
-In Apollo Server 4, the `debug` and `schemaHash` fields are no longer available on `GraphQLRequestContext`. Note that `GraphQLRequestContext` always returns the `response` and `http` fields.
+The `debug` field has been removed, because `ApolloServer` no longer has a vague `debug` option that affects multiple unrelated features. There is no direct replacement for it; if this is a problem for you, please open a GitHub issue and we can come up with an appropriate improvement (perhaps making `nodeEnv` or `includeStackTracesInErrorResponses` available as public readonly fields on `ApolloServer`).
-The `schemaHash` field was an unstable hash of the introspection JSON of a schema, created for the `apollo-server-plugin-operation-registry` package. Note that the `schemaHash` field is different from the hash of the schema SDL, which schema reporting still uses.
+### Fields on `GraphQLServerContext`
-Additionally, Apollo Server 4 removes the `persistedQueries` field from `GraphQLServerContext`.
+The TypeScript type for the argument to the `serverWillStart` plugin hook has been renamed from `GraphQLServiceContext` to `GraphQLServerContext`, for consistency with the hook name.
-The `logger` and `cache` fields are no longer on `GraphQLRequestContext`. Instead, `GraphQLRequestContext` has a `server: ApolloServer` field, and `logger` and `cache` are public readonly fields on `ApolloServer`.
+The `logger` field has been. This field is now available as a public readonly field on the `ApolloServer` object, and `GraphQLServerContext` now provides the `ApolloServer` object in a new field `server`, so `serviceContext.logger` can be replaced with `serverContext.server.logger`.
-The `logger` field is no longer part of the argument to `serverWillStart`, but `server` is instead, and `logger` is a public readonly field on `ApolloServer`.
+The `schemaHash` field has been removed; see the previous section for details.
+
+The `persistedQueries` field has been removed. We did not know of a use case for providing this particular bit of configuration to plugins (other than to a very old version of the operation cache plugin that used it). If having this available in plugins is important for you, please file a GitHub issue.
+
+The `serverlessFramework` field has been removed. The new `startedInBackground` field provides essentially the same information. (In AS3, `serverlessFramework` was true if you were using a subclass of `ApolloServer` designed for a serverless framework, which mostly affected startup error handling. In AS4, there are no subclasses; the API that implements startup error handling in a serverless-friendly way is the new `server.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()` method, and the `startedInBackground` field is true if the server was started with this method instead of with `server.start()` or something that calls `server.start()` such as `startStandaloneServer()`.)
### Older Gateway types
-In Apollo Server 2, the TypeScript type used for `gateway` constructor options is called `GraphQLService`. In Apollo Server 3, the TypeScript type is called `GatewayInterface`.
+The `gateway` option to the `ApolloServer` constructor is designed to be used with Apollo Gateway, but can also be used with your own implementation of the gateway interface. Several changes have been made to that interface in Apollo Server 4.
-Apollo Server 4 drops the exports for both the `SchemaChangeCallback` and `GraphQLService` types. We recommend using the `GatewayInterface` type instead.
+In Apollo Server 2, the TypeScript type used for the `gateway` constructor option is called `GraphQLService`. In Apollo Server 3, the TypeScript type is called `GatewayInterface`, but the `apollo-server-core` package continued to export an identical `GraphQLService` type as well.
-This `GatewayInterface` type requires the following:
+In Apollo Server 4, the legacy `GraphQLService` type is no longer exported; use `GatewayInterface` instead.
-- The `stop` method is present
-- The `executor` method is async
-- The `apollo` option is passed to the `load` method
+In Apollo Server 3, the method `GatewayInterface.load` was declared to return `Promise`, which has a `schema` and an `executor`. In Apollo Server 4, `GraphQLServiceConfig` has been renamed to `GatewayLoadResult`, and it only has an `executor` field; the `onSchemaLoadOrUpdate` hook is sufficient to receive the schema.
-Additionally, the `ExecutionResult` type from `graphql-js` replaces the similar `GraphQLExecutionResult` type (returned by `executor`). The types are essentially the same, except that `data` and `extensions` are now `Record`, rather than `Record`.
+The TypeScript type `GraphQLExecutor` (the type of the `executor` field in the object returned from `GatewayInterface.load`) now returns the `ExecutionResult` type from `graphql-js` rather than the similar `GraphQLExecutionResult` type defined by Apollo Server 3. The types are essentially the same, except that `data` and `extensions` are now `Record`, rather than `Record`.
## Changes to framework integrations
@@ -510,7 +648,7 @@ In Apollo Server 3, you can use the `apollo-server-express` package to attach Ap
Apollo Server 4 introduces the [`expressMiddleware`](https://github.com/apollographql/apollo-server/blob/main/packages/server/src/express/index.ts) function from the `@apollo/server` package, enabling you to attach an `ApolloServer` instance to an [Express](https://expressjs.com/) server without switching packages.
-The `expressMiddleware` function accepts an `ApolloServer` instance, and as its name implies, you can set up `expressMiddleware` while adding other middleware to your `Express` server:
+The `expressMiddleware` function accepts an `ApolloServer` instance, and as its name implies, you can set up `expressMiddleware` while adding other middleware to your `Express` server. Note that while Apollo Server 3's middleware invisibly defaulted to serving requests on the URL path `/graphql`, you need to specify this explicitly when attaching your middleware to Express in Apollo Server 4.
@@ -521,7 +659,7 @@ import cors from 'cors';
import { json } from 'body-parser';
import { ApolloServer, ApolloServerPluginDrainHttpServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
-import { typeDefs, resolvers } from ('./schema');
+import { typeDefs, resolvers } from './schema';
// Set up Express
const app = express();
@@ -535,44 +673,16 @@ const server = new ApolloServer({
});
await server.start();
-// Pass an ApolloServer instance to the expressMiddleware function
-app.use(cors(), json(), expressMiddleware(server));
+// Pass an ApolloServer instance to the expressMiddleware function.
+app.use('/graphql', cors(), json(), expressMiddleware(server));
await new Promise((resolve) => httpServer.listen({ port: 4000 }, resolve));
console.log(`π Server ready at http://localhost:4000`);
```
-```js {18}
-import express from 'express';
-import http from 'http';
-import cors from 'cors';
-import { json } from 'body-parser';
-import { ApolloServer, ApolloServerPluginDrainHttpServer } from '@apollo/server';
-import { expressMiddleware } from '@apollo/server/express4';
-import { typeDefs, resolvers } from ('./schema');
-
-// Set up Express
-const app = express();
-const httpServer = http.createServer(app);
-
-// Set up Apollo Server
-const server = new ApolloServer({
- typeDefs,
- resolvers,
- plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
-});
-await server.start();
-
-// Pass an ApolloServer instance to the expressMiddleware function
-app.use(cors(), json(), expressMiddleware(server));
-await new Promise((resolve) => httpServer.listen({ port: 4000 }, resolve));
-
-console.log(`π Server ready at http://localhost:4000`);
-```
-
-Note, the `expressMiddleware` function has no runtime dependency on `express` (or any other package).
+Note: the `expressMiddleware` function has no runtime dependency on `express` (or any other package).
### New approach to serverless frameworks
@@ -602,7 +712,12 @@ Apollo Server 4's other non-serverless framework integrations expect the develop
### `debug`
-In Apollo Server 4, the `debug` constructor option has been renamed `includeStackTracesInErrorResponses`:
+In Apollo Server 3, the `debug` constructor option (which defaulted to true unless the `NODE_ENV` environment variable was set to `production` or `test`) controlled several unrelated aspects of Apollo Server:
+- When `debug` was set to true, stack traces are included on errors in GraphQL responses.
+- If Apollo Server was using its default `logger` implementation, messages sent at the `DEBUG` log level would be printed when `debug` was set to true. (Note that Apollo Server 3's core code wrote almost no messages at the `DEBUG` level, so this only made a difference if your plugins used the provided `logger` to send `DEBUG` messages.)
+- The `debug` flag was made available to plugins on `GraphQLRequestContext` to use as they wish.
+
+In Apollo Server 4, the `debug` constructor option has been removed. In its place is a new `includeStackTracesInErrorResponses` option which controls its namesake feature. Like `debug`, this option defaults to true unless the `NODE_ENV` environment variable is set to `production` or `test`. If you set `debug` in Apollo Server 3, you may want to set `includeStackTracesInErrorResponses` to the same value in Apollo Server 4.
```ts
const apolloServerInstance = new ApolloServer({
@@ -612,10 +727,23 @@ const apolloServerInstance = new ApolloServer({
});
```
-As part of this change, if you don't provide your own logger, the default log level is now set to `DEBUG` (instead of `INFO`).
+Additionally, if your server did not pass a custom `logger` to `new ApolloServer` and your app or a plugin makes use of `DEBUG`-level log messages, you will need to set the default level yourself. For example, using the same `Logger` implementation that Apollo Server uses by default:
+
+```ts
+import loglevel from 'loglevel';
+
+const logger = loglevel.getLogger('apollo-server');
+logger.setLevel(shouldShowDebugMessages ? loglevel.levels.DEBUG : loglevel.levels.INFO);
+const server = new ApolloServer({
+ logger,
+ // ...
+});
+```
+
### `Config` type name
-In Apollo Server 4, the TypeScript name of the constructor options object has changed from `Config` to the more aptly named, `ApolloServerOptions`.
+
+In Apollo Server 4, the TypeScript name of the constructor options object has changed from `Config` to the more aptly named `ApolloServerOptions`.
## Changed Features
@@ -630,37 +758,24 @@ Apollo Server 3 has a "batteries-included" `apollo-server` package designed to h
In Apollo Server 4, we introduce the `startStandaloneServer` function in the main `@apollo/server` package. The concept of the `startStandaloneServer` function is similar to the "batteries-included" `ApolloServer`, providing you with a streamlined setup experience without offering as much configuration.
Below is the high-level syntax for setting up the `startStandaloneServer` function:
+
```ts {19}
-import { ApolloServer, startStandaloneServer } from "@apollo/server";
+import { ApolloServer } from "@apollo/server";
+import { startStandaloneServer } from "@apollo/server/standalone";
// You can optionally create a TS interface to set up types
// for your context
interface MyContext {
- token: String
+ token: String;
}
// Create a new ApolloServer instance, passing in your
// context's types to ApolloServer's integration function.
const server = new ApolloServer({
-// The ApolloServer constructor requires two parameters: your schema
-// definition and your set of resolvers.
- typeDefs,
- resolvers,
-});
-
-// startStandaloneServer returns a promise containing the URL where
-// your server is listening
-const { url } = await startStandaloneServer(server, options)
-```
-
-```js {11}
-import { ApolloServer, startStandaloneServer } from "@apollo/server";
-
-// The ApolloServer constructor requires two parameters: your schema
-// definition and your set of resolvers.
-const server = new ApolloServer({
+ // The ApolloServer constructor requires two parameters: your schema
+ // definition and your set of resolvers.
typeDefs,
resolvers,
});
@@ -677,7 +792,7 @@ The `startStandaloneServer` function accepts two arguments, the first is the ins
| Name | Description |
|---|---|
| `context` | You can optionally provide a [`context` initialization _function_](#context-initialization-function), which should return an object.
|
-| `listen` | These options are passed to the `listen` method of the under-the-hood `http.Server`.
Supported options are listed in the documentation for [net.Server.listen](https://nodejs.org/api/net.html#net_server_listen_options_callback).
|
+| `listen` | These options are passed to the `listen` method of the under-the-hood `http.Server`, similar to the arguments passed to `server.listen()` in Apollo Server 3. Note that this only supports the object form of listen options, such as `{port: 4000}` instead of the number `4000` implying port.
Supported options are listed in the documentation for [net.Server.listen](https://nodejs.org/api/net.html#net_server_listen_options_callback). |
Below is a complete example of setting up the `startStandaloneServer` function:
@@ -709,12 +824,12 @@ console.log(`π Server listening at: ${url}`);
-Note, the `startStandaloneServer` function has a runtime dependency on `express`.
-
### Default CSRF prevention
-CSRF prevention was added to Apollo Server 3.7+ and is now on by default in Apollo Server 4. For more information about CSRF prevention and CORS, see [Configuring CORS](/apollo-server/security/cors).
+
+Apollo Server 3.7 added a recommended security feature called CSRF prevention, which could be enabled with the constructor option `csrfPrevention: true`. In Apollo Server 4, `true` is the default value. If you want to disable this recommended security feature, pass `csrfPrevention: false`. For more information about CSRF prevention and CORS, see [Configuring CORS](/apollo-server/security/cors).
### Combining packages into `@apollo/server`
+
Apollo Server 4 takes many previously separate npm packages from Apollo Server 3 and combines them into a single, easy-to-remember `@apollo/server` package.
The following packages have all been incorporated into the `@apollo/server` package:
@@ -744,7 +859,7 @@ const server = new ApolloServer({
}));
```
-In Apollo Server 4, the `context` function is a named argument passed into your middleware function, which is required if your `ApolloServer` instance is not using the default `BaseContext` type. The `context` function should return an object, which is then accessible to your [server's resolvers](/apollo-server/data/resolvers/#the-context-argument).
+In Apollo Server 4, the `context` function is a named argument passed into your web integration function (such as `expressMiddleware` or `startStandaloneServer`). `ApolloServer` itself now has a generic type parameter specifying the type of your context value. The `context` function should return an object, which is then accessible to your [server's resolvers](/apollo-server/data/resolvers/#the-context-argument) and to plugins as the `contextValue` field.
Below is an example of providing a `context` initialization function to the `startStandaloneServer` function:
@@ -770,20 +885,6 @@ const { url } = await startStandaloneServer(server, {
})
```
-```js {7-9}
-const server = new ApolloServer({
- typeDefs,
- resolvers,
-});
-
-const { url } = await startStandaloneServer(server, {
- context: async ({ req, res }) => ({
- token: await getTokenForRequest(req),
- }),
- listen: { port: 4000 },
-});
-```
-
The `context` function's syntax is similar for the `expressMiddleware` function:
@@ -814,33 +915,15 @@ app.use(
);
```
-```js {11-13}
-const server = new ApolloServer({
- typeDefs,
- resolvers,
-});
-
-await server.start();
-const app = express();
-
-app.use(
- expressMiddleware(server, {
- context: async ({ req, res }) => ({
- token: await getTokenForRequest(req),
- }),
- }),
-);
-```
-
-Note, the objects passed to the `context` initialization function are `http.IncomingMessage` and `http.ServerResponse` objects, not their Express subclasses.
+Note that when using `expressMiddleware`, the `req` and `res` objects passed to the `context` function are of type `express.Request` and `express.Response`, but when using `startStandaloneServer`, they are of type `http.IncomingMessage` and `http.ServerResponse`. If you need to use Express-specific properties in your context function, you should use `expressMiddleware`.
### Improved typing for `context`
-In Apollo Server 3, the TypeScript typing for `context` relies on the _arguments_ to the context function instead of the _contents_ of the actual context object. This means you don't get proper type inference for `context` in your resolvers, inline plugins, etc.
+In Apollo Server 3, you don't tell TypeScript what type your context value is, so there is no compile-time check that the type returned by your `context` function matches the context value type read by your resolvers and plugins. `ApolloServer` does have a generic parameter, but that parameter is the type of the arguments *passed to* your context function (and is specified by your web integration) rather than your app's context value type.
-In Apollo Server 4, you can type your `context` by passing an argument to `ApolloServer`'s integration function. This gives you proper `context` typing throughout, providing you with `context` type inference and enabling you to ensure your `context` object is complete before executing requests.
+In Apollo Server 4, you can type your `context` by passing an argument to `ApolloServer`'s integration function. This gives you proper `context` typing throughout, providing you with `context` type inference and enabling you to ensure your `context` object is complete before executing requests. (We no longer need a generic parameter for the type of the arguments to the context function, since the context function is passed directly to the framework-specific middleware function such as `expressMiddleware` which can define the correct type directly.)
You can set up `context` TypeScript typing with `ApolloServer`, like so:
@@ -871,56 +954,46 @@ const { url } = await startStandaloneServer(apolloServerInstance, {
});
```
-### Renamed `contextValue`
+### `executeOperation` accepts `context` object
-In Apollo Server 3, the name `context` can refer to either a _function_ that returns a context object or the _values_ within your GraphQL context.
+The [`server.executeOperation`](/apollo-server/api/apollo-server/#executeoperation) method enables you to execute GraphQL operations by specifying the operation text directly rather than by specifying them as an HTTP request. This is especially helpful for testing.
-In Apollo Server 4, we clarify this by continuing to use `context` as the name of the _function_:
+In Apollo Server 3, you specify the operation's context value indirectly by passing a second optional argument which is then passed to your `ApolloServer` instance's `context` function. So for example, if you're using `apollo-server-express`, you would somehow construct an Express request and response and pass them to `executeOperation` as a `{ req, res }` object.
-
+In Apollo Server 4, the `executeOperation` method instead takes a context value directly. This bypasses your `context` function. (If you'd like to test the behavior of the context function, we recommend running actual HTTP requests against your server.)
-```ts {13}
-const { url } = await startStandaloneServer(apolloServerInstance, {
- // This function is called for every incoming operation, and
- // returns an object that is available from your resolvers
- async context() {
- return {
- token: await getTokenForRequest(req),
- };
- },
- listen: { port: 4000 },
-});
-```
+So a test like this in Apollo Server 3:
-
+
-Whereas fields containing a specific `context` _value_ (such as on `GraphQLRequestContext`, the first argument to all plugin functions) are now named `contextValue`:
+interface MyContext {
+ name?: string;
+}
-```ts
-new ApolloServer<{ foo: number }>({
- typeDefs: `type Query {foo: String}`,
+const server = new ApolloServer({
+ typeDefs: "type Query { hello: String!}",
resolvers: {
Query: {
- n(_parent: any, _args: any, context): number {
- return context.foo;
- },
+ hello: (_, __, context) => `Hello ${context.name}!`,
},
},
- plugins: [
- {
- async requestDidStart({ contextValue }) {
- let n: number = contextValue.foo;
- },
- },
- ],
+ context: async ({ req }) => ({ name: req.headers.name }),
});
-```
-### `executeOperation` accepts `context` object
+const { result } = await server.executeOperation({
+ query: 'query helloContext { hello }',
+}, {
+ // A half-hearted attempt at making something vaguely like an express.Request,
+ // and not bothering to make the express.Response at all.
+ req: { headers: { name: 'world' } },
+});
-The [`server.executeOperation`](/apollo-server/api/apollo-server/#executeoperation) method enables you to test GraphQL operations through Apollo Server's request pipeline without sending an HTTP request. In Apollo Server 3, the `executeOperation` method accepts a second optional argument which is passed to an `ApolloServer` instance's `context` function.
+expect(result.data?.hello).toBe('Hello world!'); // -> true
+```
-In Apollo Server 4, you can directly pass an object to use as the `context` for the `executeOperation` method. This lets you unit-test your `context` function's behavior directly:
+
+
+could be changed to something like this in Apollo Server 4:
@@ -931,45 +1004,18 @@ interface MyContext {
const server = new ApolloServer({
typeDefs: "type Query { hello: String!}",
- resolvers:
+ resolvers: {
Query: {
hello: (_, __, context) => `Hello ${context.name}!`,
},
-});
-
-const { result } = await server.executeOperation(
- {
- query: 'query helloContext { hello }',
- },
- // This second optional argument is used as the context object
- {
- name: 'world',
},
-);
-
-
-expect(result.data?.hello).toBe('Hello world!'); // -> true
-```
-
-```js {13-17}
-const server = new ApolloServer({
- typeDefs: "type Query { hello: String!}",
- resolvers:
- Query: {
- hello: (_, __, context) => `Hello ${context.name}!`,
- },
});
-const { result } = await server.executeOperation(
- {
- query: 'query helloContext { hello }',
- },
- // This second optional argument is used as a context object
- // for executeOperation
- {
- name: 'world',
- },
-);
+const { result } = await server.executeOperation({
+ query: 'query helloContext { hello }',
+}, {
+ name: 'world',
+});
expect(result.data?.hello).toBe('Hello world!'); // -> true
```
@@ -982,74 +1028,7 @@ Apollo Server supports [batching HTTP requests](/apollo-server/requests/#batchin
In Apollo Server 4, you must explicitly enable this feature by passing `allowBatchedHttpRequests: true` to the `ApolloServer` constructor.
-Not all GraphQL clients support HTTP batching, and incremental support isn't currently possible. HTTP batching can help performance by sharing a `context` object across operations, but it can make it harder to understand the amount of work any given request does.
-
-### `addPlugin` function
-Apollo Server 4 introduces a new public function on the `ApolloServer` class, `addPlugin`. The `addPlugin` function enables you to add plugins to `ApolloServer` _before_ you start a server (i.e., before calling `server.start()`):
-
-
-
-```ts
-import express from 'express';
-import http from 'http';
-import cors from 'cors';
-import { json } from 'body-parser';
-import { ApolloServer, ApolloServerPluginDrainHttpServer } from '@apollo/server';
-import { expressMiddleware } from '@apollo/server/express4';
-
-import { typeDefs, resolvers } from ('./schema');
-
-const server = new ApolloServer({
- typeDefs,
- resolvers,
-});
-
-const app = express();
-const httpServer = http.createServer(app);
-
-// Add our ApolloServerPluginDrainHttpServer plug in *before* starting the server
-server.addPlugin(ApolloServerPluginDrainHttpServer({ httpServer }));
-
-await server.start();
-// Set up express middleware with body-parsing and cors
-app.use(cors(), json(), expressMiddleware(server));
-await new Promise((resolve) => httpServer.listen({ port: 4000 }, resolve));
-
-console.log(`π Server ready at http://localhost:4000`);
-```
-
-```js
-import express from 'express';
-import http from 'http';
-import cors from 'cors';
-import { json } from 'body-parser';
-import { ApolloServer, ApolloServerPluginDrainHttpServer } from '@apollo/server';
-import { expressMiddleware } from '@apollo/server/express4';
-
-import { typeDefs, resolvers } from ('./schema');
-
-const server = new ApolloServer({
- typeDefs,
- resolvers,
-});
-
-const app = express();
-const httpServer = http.createServer(app);
-
-// Add our ApolloServerPluginDrainHttpServer plug in *before* starting the server
-server.addPlugin(ApolloServerPluginDrainHttpServer({ httpServer }));
-
-await server.start();
-// Set up express middleware with body-parsing and cors
-app.use(cors(), json(), expressMiddleware(server));
-await new Promise((resolve) => httpServer.listen({ port: 4000 }, resolve));
-
-console.log(`π Server ready at http://localhost:4000`);
-```
-
-
-
-The new `addPlugin` function is useful if you'd like to pass the server itself to a pluginβs constructor.
+Not all GraphQL clients support HTTP batching, and batched requests will not support incremental delivery when Apollo Server implements that feature. HTTP batching can help performance by sharing a `context` object across operations, but it can make it harder to understand the amount of work any given request does.
### `@apollo/utils.fetcher` for TypeScript typing
@@ -1057,9 +1036,7 @@ In Apollo Server 3, the `apollo-server-env` package primarily provides TypeScrip
Apollo Server 4 introduces `@apollo/utils.fetcher`, which defines a minimal fetch API (`Fetcher`) that provides Fetch API TypeScript typings.
-With this change, we are also removing the `requestAgent` option from the [usage reporting plugin](/apollo-server/api/plugin/usage-reporting/) because `requestAgent` predates the `fetcher` option.
-
-Where previously, you would write:
+With this change, we are also removing the `requestAgent` option from the [usage reporting plugin](/apollo-server/api/plugin/usage-reporting/), because `requestAgent` is specific to the `node-fetch` implementation of the Fetch API. If you used `requestAgent` like this:
```ts
ApolloServerPluginUsageReporting({ requestAgent })
```
@@ -1078,11 +1055,13 @@ You can now write:
### Default cache is bounded
-By default, Apollo Server uses an in-memory cache backend to optimize the performance of several features (including APQs, the response cache plugin, and `RESTDataSource`).
+Each Apollo Server has a cache that is used for several features, such as APQs, the response cache plugin, and `RESTDataSource`. This cache can be in-memory or use a server such as Redis, and is configured with the `cache` constructor option.
+
+In Apollo Server 3, the default cache is an unbounded in-memory cache. This is vulnerable to denial of service attacks via memory exhaustion, and we recommend that users do not use this default cache.
-Versions of Apollo Server before 3.9 use the `apollo-server-caching` package to implement this in-memory cache. The `apollo-server-caching` package is no longer maintained, and we do not recommend using it. By default, [versions of Apollo Server 3.9+](https://github.com/apollographql/apollo-server/blob/HEAD/CHANGELOG.md#v390) use an unbounded cache under the hood, which is _not safe_ for production use. To learn more, see [Configuring cache backends](/apollo-server/performance/cache-backends).
+In Apollo Server 4, the default cache is a bounded in-memory cache backend (which _is safe_ for production use). This is equivalent to passing `cache: 'bounded'` in Apollo Server 3.9 or newer.
-By default, Apollo Server 4 uses a bounded in-memory cache backend (which _is safe_ for production use). If you want to customize the cache Apollo Server uses, Apollo provides two wrapper packages to help with this process:
+If you want to customize the cache Apollo Server uses, Apollo provides two wrapper packages to help with this process:
* [`@apollo/utils.keyvadapter`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyvAdapter) - provides a [`KeyvAdapter`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyvAdapter#keyvadapter-class) wrapper class to use alongside the [`keyv`](https://www.npmjs.com/package/keyv) package.
* [`@apollo/utils.keyvaluecache`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache) - provides both the [`KeyValueCache`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache#keyvaluecache-interface) TypeScript interface and a [`InMemoryLRUCache`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache#inmemorylrucache) class (a wrapper around the `lru-cache` package).
@@ -1119,7 +1098,7 @@ For example, below is a valid query:
```json
{
- βqueryβ: β{ __typename }β, extensions: { βfooβ: 1 }
+ "query": "{ __typename }", extensions: { "foo": 1 }
}
```
@@ -1127,13 +1106,37 @@ Whereas this query would be invalid:
```json
{
- βqueryβ: β{ __typename }β, extensions: β{ \βfoo\β: 1 }β
+ "query": "{ __typename }", extensions: "{ \"foo\": 1 }"
}
```
-### Local landing page defaults to Apollo Sandbox
+### Local landing page defaults to Embedded Apollo Sandbox
+
+In Apollo Server 3, the default development landing page is a splash page containing a link to Apollo Sandbox hosted at https://studio.apollographql.com/. This hosted Sandbox only works if your server's CORS configuration allows the origin https://studio.apollographql.com/ to talk to it. You can also configure `ApolloServerPluginLandingPageLocalDefault` with `embed: true` to embed Apollo Sandbox directly in the landing page; in this mode, Sandbox is able to make same-origin requests to your server and no CORS configuration is necessary.
+
+In Apollo Server 4, the default development landing page is the embedded Apollo Sandbox. Note that nothing changes about the default production landing page.
+
+To restore the splash page, write:
+
+
+
+```ts
+import { ApolloServer } from '@apollo/server';
+import { ApolloServerPluginLandingPageLocalDefault, ApolloServerPluginLandingPageProductionDefault }
+ from '@apollo/server/plugin/landingPage/default';
+
+new ApolloServer({
+ // ...
+ plugins: [
+ process.env.NODE_ENV === 'production'
+ ? ApolloServerPluginLandingPageProductionDefault()
+ : ApolloServerPluginLandingPageLocalDefault({ embed: false })
+ ],
+});
+```
+
+
-Apollo Server 4's default development landing page is an embedded Apollo Sandbox, enabling you to run GraphQL operations with no additional CORS setup. If you want to use Apollo Server's default landing page instead, pass `ApolloServerPluginLandingPageLocalDefault({embed: false})` to the plugins of your `ApolloServer` constructor.
### Warning for servers without draining
@@ -1144,13 +1147,18 @@ In Apollo Server 4, if your server _hasn't_ set up draining and it receives an o
If you are using the `startStandaloneServer` function, your server drains automatically. If you are using `expressMiddleware` or another `http.Server`-based web server, you can add draining using the [`ApolloServerPluginDrainHttpServer` plugin](/apollo-server/api/plugin/drain-http-server/#using-the-plugin).
### `CacheScope` type
-In Apollo Server 4, `CacheScope` is now a union of strings (`PUBLIC` or `PRIVATE`):
+In Apollo Server 4, `CacheScope` is now a union of strings (`PUBLIC` or `PRIVATE`) rather than an enum:
```ts
export type CacheScope = 'PUBLIC' | 'PRIVATE';
```
-This means you can use the string `PUBLIC` directly instead of `CacheScope.Public`.
+You can no longer type `CacheScope.Public` or `CacheScope.Private`. Instead, just use the string `'PUBLIC'` or `'PRIVATE'`. Values defined as `CacheScope` will only accept those two values, so typos will still be caught at compile time.
+
+
+### `GraphQLRequest`
+
+Apollo Server 4 refactors the `GraphQLRequest` object (e.g., `requestContext.request`). Specifically, its `http` field is now a new `HTTPGraphQLRequest` type instead of a type based on the Fetch API `Request` object. This object does not contain the URL path, and its `headers` field is a `Map` (with lower-case keys) rather than a Fetch API `Headers` object.
### `GraphQLResponse`
@@ -1166,8 +1174,13 @@ export interface GraphQLResponse {
}
```
+
Additionally, the `data` and `extensions` fields are both type `Record`, rather than `Record`.
+`http.headers` is now a `Map` (with lower-case keys) rather than a Fetch API `Headers` object.
+
+Note: we plan to implement experimental support for incremental delivery (`@defer`/`@stream`) before the v4.0.0 release, and we expect that this will change the structure of `GraphQLResponse` further.
+
### `@apollo/server-plugin-operation-registry`
The plugin `apollo-server-plugin-operation-registry` has been renamed `@apollo/server-plugin-operation-registry`.
From 1937b78540cab3d7034427d0b40132102945f15c Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Mon, 18 Jul 2022 15:05:24 -0700
Subject: [PATCH 03/19] make it build
---
docs/source/migration.mdx | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index 8b77e401bc3..d81ee1778a0 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -966,6 +966,7 @@ So a test like this in Apollo Server 3:
+```ts
interface MyContext {
name?: string;
}
From ee3fb418cbe880131596873ce28187ef9635c639 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Mon, 18 Jul 2022 18:55:30 -0700
Subject: [PATCH 04/19] Reorganize and rework migration some more
---
docs/source/migration.mdx | 758 ++++++++++++++++----------------------
1 file changed, 319 insertions(+), 439 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index d81ee1778a0..f718d5dc233 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -18,13 +18,41 @@ During Apollo Server 4's alpha, we are actively looking to gather feedback and [
> For a list of all breaking changes, see the [changelog](https://github.com/apollographql/apollo-server/blob/main/CHANGELOG.md).
-## Basic migration examples
+## Package-level changes
-(TODO: better name for this section.)
+TODO: Maybe rename section?
-This migration guide describes everything that has changed in Apollo Server 4 in detail. But first, here's a high-level example of how using Apollo Server changes in the most common cases.
+Apollo Server 3 ships with a fixed set of integrations with a variety of web frameworks and serverless environments, but does not provided a supported mechanism for integrating with additional frameworks. In Apollo Server 3, changes to framework integrations could only be released with lockstep versioning with Apollo Server itself, which has made it challenging to support multiple major versions of frameworks or make other integration-specific changes. Each of these integrations are released in a separate package, such as `apollo-server-express` or `apollo-server-lambda`. The core logic is implemented in a variety of packages, most notably `apollo-server-core`. This package defines an `ApolloServer` "base" class, and each integration package exports a subclass with the same name with slightly different APIs. Additionally, the `apollo-server` package is a "batteries-included" package which wraps `apollo-server-express` and provides a full HTTP server without the need to learn about a particular web framework, while providing minimal opportunities for HTTP-level customization.
-### Migrating from `apollo-server` to `startStandaloneServer`
+Apollo Server 4 takes a different approach. The Apollo Server core team no longer maintains most of these integrations. Instead, Apollo Server now has a simple stable web framework integration API (including explicit support for serverless framework life cycles). The new `@apollo/server` package contains the `ApolloServer` class, as well as an Express 4 integration (similar to AS3's `apollo-server-express` package) and a standalone server (similar to AS3's `apollo-server` package). There are no subclasses in AS4: there is a single `ApolloServer` class with a single API, and integrations use that API.
+
+The Apollo Server core team no longer maintains the other integrations. We will work with the broader open source community, allowing users of other web frameworks to make the best choices for their framework's integrations rather than expecting the core team to be intimately familiar with the best practices of a dozen different projects. Our hope is that there will exist upgrade paths for all of AS3's integrations by the time we release v4.0.0; if you'd like to help, we have [an issue calling for maintainers for each integration](https://github.com/apollographql/apollo-server/labels/integration-collaborators).
+
+For those migrating from Apollo Server 3 to Apollo Server 4, use the below flowchart to see your migration path:
+
+```mermaid
+graph TB;
+ server("Am I using the apollo-server package?");
+ server--No-->express("Am I using the apollo-server-express package?");
+ server--Yes-->useStandAlone("Use the startStandaloneServer
function");
+ express--No-->buildIntegration("You canβt upgrade during the alpha yet*");
+ express--Yes-->useExpressMiddleware("Use the expressMiddleware
function");
+ class useStandAlone,useExpressMiddleware secondary;
+```
+
+If you are currently using the `apollo-server` package, you should use the [`startStandaloneServer`](#startstandaloneserver-function) function. If you are using the `apollo-server-express` package, you should use the [`expressMiddleware`](#expressmiddleware) function. These functions, as well as the `ApolloServer` class, are exported from the new `@apollo/server` package.
+
+If you are using any other Apollo Server 3 framework integration package, you canβt upgrade during the AS4 alpha release _yet_. Please help us by [building new integrations](/building-integrations) or [discussing how to maintain existing integrations](https://github.com/apollographql/apollo-server/labels/integration-collaborators) to ensure there is an Apollo Server 4 integration for your favorite framework.
+
+There are a few other high-level changes to how you work with framework integrations. There are more details on each of these changes in later sections.
+
+- In Apollo Server 3, you pass your `context` function to the `ApolloServer` constructor. The parameters received by this function depend on which `ApolloServer` subclass you are using. Because Apollo Server 4 does not use subclassing, you no longer pass your `context` function to the `ApolloServer` constructor; instead, you pass it to your integration function (eg, `expressMiddleware` or `startStandaloneServer`).
+- In Apollo Server 3, the framework integrations automatically set up their framework's HTTP body parsing and CORS header writing for you, and you could configure that functionality in a framework-specific way via the Apollo Server API. In Apollo Server 4, it's your responsibility to set up these standard features yourself. Specifically, when using `expressMiddleware`, you should install the `body-parser` and `cors` npm packages and use them in your Express app, just like with any other JSON-based API server. Note that `startStandaloneServer` does set up these packages for you automatically, but does not allow you to configure their behavior.
+- In Apollo Server 3, some framework integrations take a `path` option that lets you configure on what URL path they listen on, with a default of `/graphql`. This feature overlapped with the router features defined by web frameworks and has been removed in Apollo Server 4. This means that to provide the same API when migrating, you'll want to explicitly mount `expressMiddleware` at `/graphql`. (Note that the AS3 batteries-included server `apollo-server` listened on all paths, not just `/graphql`.)
+
+The follow sections show how servers using `apollo-server` and `apollo-server-express` need to change to use the new API.
+
+### Migrating from `apollo-server`
If you used the batteries-included `apollo-server` package in Apollo Server 3, you'll want to use the `startStandaloneServer` function in Apollo Server 4. Call `startStandaloneServer(server)` instead of `server.listen()`. Note that you cannot configure CORS settings with `startStandaloneServer`; if you want to change CORS settings from the default, use `expressMiddleware` instead.
@@ -45,7 +73,7 @@ async function startApolloServer() {
resolvers,
context: async ({ req }) => ({ token: req.headers.token }),
});
- const { url } = await server.listen(4444);
+ const { url } = await server.listen(4000);
console.log(`π Server ready at ${url}`);
}
```
@@ -68,7 +96,7 @@ async function startApolloServer() {
const server = new ApolloServer({ typeDefs, resolvers });
const { url } = await startStandaloneServer(server, {
context: async ({ req }) => ({ token: req.headers.token }),
- listen: { port: 4444 },
+ listen: { port: 4000 },
});
console.log(`π Server ready at ${url}`);
}
@@ -77,9 +105,15 @@ async function startApolloServer() {
-### Migrating from `apollo-server-express` to `expressMiddleware`
+### Migrating from `apollo-server-express`
-If you used the `apollo-server-express` package in Apollo Server 3, you'll want to use the `expressMiddleware` function in Apollo Server 4 instead of the `applyMiddleware` method. Note that by default, `apollo-server-express` in AS3 would only actually respond to operations on `/graphql`, so we explicitly mount `expressMiddleware` at that path in AS4.
+If you used the `apollo-server-express` package in Apollo Server 3, you'll want to use the `expressMiddleware` function in Apollo Server 4 instead of the `applyMiddleware` method. The changes include:
+
+- Installing `@apollo/server`, `cors`, and `body-parser` instead of `apollo-server-express` and `apollo-server-core`
+- Importing symbols from `@apollo/server` instead of `apollo-server-express` and `apollo-server-core`
+- Explicitly adding `cors` and `bodyParser.json()
+
+Note that by default, `apollo-server-express` in AS3 would only actually respond to operations on `/graphql`, so we explicitly mount `expressMiddleware` at that path in AS4.
@@ -116,12 +150,14 @@ async function startApolloServer() {
```ts title="apollo-server-4.ts"
-// npm install @apollo/server express graphql
+// npm install @apollo/server express graphql cors body-parser
import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
import express from 'express';
import http from 'http';
+import cors from 'cors';
+import { json } from 'body-parser';
import { typeDefs, resolvers } from './schema';
interface MyContext {
@@ -137,9 +173,13 @@ async function startApolloServer() {
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});
await server.start();
- app.use('/graphql', expressMiddleware(server, {
- context: async ({ req }) => ({ token: req.headers.token }),
- }));
+ app.use('/graphql',
+ cors(),
+ json(),
+ expressMiddleware(server, {
+ context: async ({ req }) => ({ token: req.headers.token }),
+ }),
+ );
await new Promise(resolve => httpServer.listen({ port: 4000 }, resolve));
console.log(`π Server ready at http://localhost:4000/graphql`);
}
@@ -148,53 +188,9 @@ async function startApolloServer() {
-## Bumped dependencies
-
-### Node.js
-Apollo Server 4 supports Node.js 14 and later. (Apollo Server 3 supports Node.js 12.) This includes all [LTS and Current versions at the time of release](https://nodejs.org/en/about/releases/).
-
-If you're using Node.js 12, upgrade your runtime before upgrading to Apollo Server 4.
-
-### `graphql`
-
-Apollo Server has a peer dependency on [`graphql`](https://www.npmjs.com/package/graphql) (the core JS GraphQL implementation). Apollo Server 4 supports `graphql` v16.3.0 and later. (Apollo Server 3 supported `graphql` v15.3.0 through v16.)
-
-If you're using an older version of `graphql`, upgrade it to a supported version before upgrading to Apollo Server 4.
-
-## Removed integrations
-
-Apollo Server 3 ships with a fixed set of integrations with a variety of web frameworks and serverless environments, but does not provided a supported mechanism for integrating with additional frameworks. In Apollo Server 3, changes to framework integrations could only be released with lockstep versioning with Apollo Server itself, which has made it challenging to support multiple major versions of frameworks or make other integration-specific changes.
-
-Apollo Server 4 takes a different approach. The Apollo Server core team no longer maintains most of these integrations. Instead, Apollo Server now has a simple stable web framework integration API (including explicit support for serverless framework life cycles). The core `@apollo/server` package contains an Express 4 integration (similar to AS3's `apollo-server-express` package) and a standalone server (similar to AS3's `apollo-server` package). All other integrations can be maintained by the broader open source community, allowing users of other web frameworks to make the best choices for their framework's integrations rather than expecting the core team to be intimately familiar with the best practices of a dozen different projects.
-
-For those migrating from Apollo Server 3 to Apollo Server 4, use the below flowchart to see your migration path:
-
-```mermaid
-graph TB;
- server("Am I using the apollo-server package?");
- server--No-->express("Am I using the apollo-server-express package?");
- server--Yes-->useStandAlone("Use the startStandaloneServer
function");
- express--No-->buildIntegration("You canβt upgrade during the alpha yet*");
- express--Yes-->useExpressMiddleware("Use the expressMiddleware
function");
- class useStandAlone,useExpressMiddleware secondary;
-```
-
-If you are currently using the `apollo-server` package, you should use the [`startStandaloneServer`](#startstandaloneserver-function) function. If you are using the `apollo-server-express` package, you should use the [`expressMiddleware`](#expressmiddleware) function.
-
-If you are using any other Apollo Server 3 framework integration package, you canβt upgrade during the AS4 alpha release _yet_. Please help us by [building new integrations](/building-integrations) or [discussing how to maintain existing integrations](https://github.com/apollographql/apollo-server/labels/integration-collaborators) to ensure there is an Apollo Server 4 integration for your favorite framework.
-
-Apollo Server 4 also removes the built-in dependency on the `cors` and `body-parser` libraries (excluding the `startStandaloneServer` function).
-
-TODO: show exact changes to use expressMiddleware and startStandaloneServer
-
-### Wrapping of framework-specific libraries
-
-Apollo Server 3 is distributed as a [collection of different packages](/apollo-server/integrations/middleware) for different environments and web frameworks.
+### Integrations no longer part of core
-For [several reasons](https://github.com/apollographql/apollo-server/blob/main/ROADMAP.md#replace-9-core-maintained-bindings-with-a-stable-http-abstraction), these additional core-maintained integrations have caused friction in the development process, slowing down work on Apollo Server.
-
-Apollo Server 4 replaces this static set of hard-coded integrations
-with a stable API. Apollo Server 4's well-defined API enables collaborating developers to [maintain](https://github.com/apollographql/apollo-server/labels/integration-collaborators) and [build new integrations](/building-integrations) for the frameworks they know best.
+The Apollo Server core team is no longer maintaining the following integration packages in Apollo Server 4. We are [looking for collaborators](https://github.com/apollographql/apollo-server/labels/integration-collaborators) who actively use these platforms to maintain AS4-compatible integration packages and will add links here once they exist.
Apollo Server 4 removes the below integration packages:
* [`apollo-server-fastify`](https://www.npmjs.com/package/apollo-server-fastify)
@@ -206,60 +202,48 @@ Apollo Server 4 removes the below integration packages:
* [`apollo-server-cloudflare`](https://www.npmjs.com/package/apollo-server-cloudflare)
* [`apollo-server-azure-functions`](https://www.npmjs.com/package/apollo-server-azure-functions)
-> We are looking for volunteers to help [build](/integrations/building-integrations) and maintain these integrations! [Join the discussion](https://github.com/apollographql/apollo-server/labels/integration-collaborators) about your favorite web framework today.
+Additionally, in Apollo Server 3 the `apollo-server-express` package supported both Express and its older predecessor [Connect](https://github.com/senchalabs/connect) using the same code. In Apollo Server 4, `expressMiddleware` no longer supports Connect. An interested developer could [build a Connect-specific middleware](/integrations/building-integrations) using the Apollo Server 4 API. A PR to this migration guide is welcome if someone does this!
+
+### Other packages merged into `@apollo/server`
+
+As described above, the functionality provided by the `apollo-server-core`, `apollo-server`, and `apollo-server-express` packages in AS3 has been combined into the single `@apollo/server` package in AS4.
+
+But wait: there's more! The following packages have *also* been combined into `@apollo/server`:
+- [`apollo-server-errors`](https://www.npmjs.com/package/apollo-server-errors)
+- [`apollo-server-plugin-base`](https://www.npmjs.com/package/apollo-server-plugin-base)
+- [`apollo-server-types`](https://www.npmjs.com/package/apollo-server-types)
-### `body-parser` & `cors`
+### Other renamed packages
-In Apollo Server 3, each web framework integration was responsible for three things: applying CORS configuration, parsing the request message's body as JSON, and processing the JSON body as a GraphQL operation. Typically, the integration used CORS and body-parsing middleware from the framework (such as the [`cors`](https://github.com/expressjs/cors) or [`body-parser`](https://www.npmjs.com/package/body-parser) libraries for Express) to implement the first two steps, taking `cors` and `bodyParserConfig` options which were directly passed through to the underlying libraries. The types of these arguments differed across web frameworks, and some integrations didn't support them at all (eg, serverless integrations where body parsing is built into the infrastructure).
+The `apollo-server-plugin-response-cache` and `apollo-server-plugin-operation-registry` plugin packages have been renamed to `@apollo/server-plugin-response-cache` and `@apollo/server-plugin-operation-registry` respectively.
-Apollo Server 4's framework integrations are now only responsible for the third step. Users are expected to use their framework's CORS and body-parsing tools directly just like with any other JSON-based API server. When migrating from a package such as `apollo-server-express` to a function such as `expressMiddleware`, you should now set up CORS and body parsing yourself.
+The [`apollo-reporting-protobuf`](https://www.npmjs.com/package/apollo-reporting-protobuf) (which is an internal implementation detail of the usage reporting plugin) has been renamed to `@apollo/usage-reporting-protobuf`.
-TODO: Rewrite example as before and after (or just refer to the main example)
+Note that once AS4 is released, all actively maintained Apollo packages will start with `@apollo/`. This leaves the `apollo-` namespace open for community integration packages (e.g., `apollo-server-fastify`).
-Below is an example of setting up `cors` and `body-parser` using the [`expressMiddleware`](#expressmiddleware) function:
-
+## Bumped dependencies
-```ts
-import { ApolloServer, ApolloServerPluginDrainHttpServer } from '@apollo/server';
-import { expressMiddleware } from '@apollo/server/express4';
-import express from 'express';
-import http from 'http';
-import cors from 'cors';
-import bodyParser from 'body-parser';
+### Node.js
-// Set up Express
-const app = express();
-const httpServer = http.createServer(app);
+Apollo Server 4 supports Node.js 14 and later. (Apollo Server 3 supports Node.js 12.) This includes all [LTS and Current versions at the time of release](https://nodejs.org/en/about/releases/).
-// Set up Apollo Server
-const server = new ApolloServer({
- typeDefs,
- resolvers,
- plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
-});
-await server.start();
+If you're using Node.js 12, upgrade your runtime before upgrading to Apollo Server 4.
-// We set up our Express server's middleware:
-// 1. using the `cors` and `body-parser` libraries, and
-// 2. passing in an `ApolloServer` instance to the `expressMiddleware` function,
-// attaching Apollo Server to our Express server
-app.use(cors(), bodyParser.json(), expressMiddleware(server));
-await new Promise((resolve) => httpServer.listen({ port: 4000 }, resolve));
+### `graphql`
-console.log(`π Server ready at http://localhost:4000`);
-```
+Apollo Server has a peer dependency on [`graphql`](https://www.npmjs.com/package/graphql) (the core JS GraphQL implementation). Apollo Server 4 supports `graphql` v16.3.0 and later. (Apollo Server 3 supported `graphql` v15.3.0 through v16.)
-
+If you're using an older version of `graphql`, upgrade it to a supported version before upgrading to Apollo Server 4.
-Apollo Server 4's new [`startStandaloneServer`](#apolloserverstandalone-and-startstandaloneserver) function (e.g., the replacement for the batteries-included `apollo-server` package) does not require you to manually set up CORS or body parsing, but does not provide a mechanism for configuring these features.
-### Connect
+### `@apollo/gateway`
-[Connect](https://github.com/senchalabs/connect) is a predecessor of Express. In Apollo Server 3, the `apollo-server-express` package supported Connect in addition to Express.
+TODO: double check this (including getting numbers for 0.x and 2.x)
+
+If you use Apollo Server with Apollo Gateway, Apollo Server 4 drops support for [`@apollo/gateway` versions](/federation/api/apollo-gateway/) below v0.35.0.
-In Apollo Server 4, `expressMiddleware` no longer supports Connect. An interested developer could [build a Connect-specific middleware](/integrations/building-integrations) using the Apollo Server 4 API. A PR to this migration guide is welcome if someone does this!
## Removed constructor options
@@ -538,34 +522,35 @@ const { url } = await startStandaloneServer(server, { listen: { port: 4000 } });
console.log(`π Server listening at: ${url}`);
```
-## Removed features
-
-Several small features have been removed from Apollo Server 4.
-
-### Health checks
-
-In Apollo Server 3, the health check feature supports a simple `HTTP`-level health check that always returns a 200 status code.
+### `debug`
-Apollo Server 4 no longer supports built-in health checks. We found that running a trivial GraphQL query was a better way of checking the status of your server, because a query ensures your server successfully serves traffic _and_ performs GraphQL operations.
+In Apollo Server 3, the `debug` constructor option (which defaulted to true unless the `NODE_ENV` environment variable was set to `production` or `test`) controlled several unrelated aspects of Apollo Server:
+- When `debug` was set to true, stack traces are included on errors in GraphQL responses.
+- If Apollo Server was using its default `logger` implementation, messages sent at the `DEBUG` log level would be printed when `debug` was set to true. (Note that Apollo Server 3's core code wrote almost no messages at the `DEBUG` level, so this only made a difference if your plugins used the provided `logger` to send `DEBUG` messages.)
+- The `debug` flag was made available to plugins on `GraphQLRequestContext` to use as they wish.
-Every GraphQL server supports a trivial query that requests the [`__typename`](/apollo-server/schema/schema/#the-__typename-field) of the top-level `Query` type. This means every GraphQL server can respond to a `GET` request to a URL, such as:
+In Apollo Server 4, the `debug` constructor option has been removed. In its place is a new `includeStackTracesInErrorResponses` option which controls its namesake feature. Like `debug`, this option defaults to true unless the `NODE_ENV` environment variable is set to `production` or `test`. If you set `debug` in Apollo Server 3, you may want to set `includeStackTracesInErrorResponses` to the same value in Apollo Server 4.
-```bash
-https://your.server/?query=%7B__typename%7D
+```ts
+const apolloServerInstance = new ApolloServer({
+ typeDefs,
+ resolvers,
+ includeStackTracesInErrorResponses: true,
+});
```
-If you really want to have a health check in your HTTP server that is unrelated to the actual health of the GraphQL execution engine (like Apollo Server 3's health check feature), you can implement that in your web framework by just adding a GET handler that always succeeds.
-
-### Path parsing
-
-In Apollo Server 3, several web framework integrations allowed you to "mount" them at a particular URL path and then use the `path` option (which defaults to `/graphql`) to specify that they should actually only process requests at a deeper path.
-
-In Apollo Server 4, web framework integrations such as `expressMiddleware` expect that they will be mounted at the appropriate path in the first place using the web framework's routing features. If you used an integration such as `apollo-server-express` and did not configure `path` in AS3, then to maintain the same behavior you should explicitly mount your middleware at `/graphql`. (Note that the batteries-included `apollo-server` package in AS3 (replaced by `startStandaloneServer` in AS4) served at all URLs instead of having the default of `/graphql`.)
+Additionally, if your server did not pass a custom `logger` to `new ApolloServer` and your app or a plugin makes use of `DEBUG`-level log messages, you will need to set the default level yourself. For example, using the same `Logger` implementation that Apollo Server uses by default:
-### `__resolveObject`
+```ts
+import loglevel from 'loglevel';
-Apollo Server 4 removes the dependency on `@apollographql/apollo-tooling`, additionally removing the `__resolveObject` pseudo-resolver. The `__resolveObject` function was an undocumented predecessor to
-the [`__resolveReference`](/federation/api/apollo-subgraph/#__resolvereference) method. While we believe `__resolveObject` is a useful feature, it would work better if implemented directly in `graphql-js` rather than in Apollo Server.
+const logger = loglevel.getLogger('apollo-server');
+logger.setLevel(shouldShowDebugMessages ? loglevel.levels.DEBUG : loglevel.levels.INFO);
+const server = new ApolloServer({
+ logger,
+ // ...
+});
+```
### `formatResponse` hook
In Apollo Server 3, the `formatResponse` hook enables you to transform the structure of GraphQL response objects before they're sent to a client.
@@ -594,96 +579,73 @@ const apolloServerInstance = new ApolloServer({
});
```
-### Support for older gateway versions
-
-TODO: double check this
-
-Apollo Server 4 drops support for [`@apollo/gateway` versions](/federation/api/apollo-gateway/) below v0.35.0.
-
-### Fields on `GraphQLRequestContext`
-
-Most plugin API hooks take a `GraphQLRequestContext` object as their first argument. There are several changes to this object.
-
-The `context` field has been renamed to `contextValue`, for consistency with the `graphql-js` API and to differentiate from the `context` option to integration functions, which is a *function* returning a context value.
-
-The `logger` and `cache` fields have been removed. These fields are now available as public readonly fields on the `ApolloServer` object, and `GraphQLRequestContext` now provides the `ApolloServer` object in a new field `server`, so `requestContext.logger` and `requestContext.cache` can be replaced with `requestContext.server.logger` and `requestContext.server.cache` respectively.
-
-The `schemaHash` field has been removed. This field was a not particularly stable hash of a JSON encoding of the result of running the GraphQL introspection query against the schema. It was not guaranteed to change when the schema changed (eg, it is not affected by changes to schema directive applications). If you need a hash of the schema, you can hash the output of applying the `graphql-js` `printSchema` function to the `schema` field (perhaps with some sort of memoization).
-
-The `debug` field has been removed, because `ApolloServer` no longer has a vague `debug` option that affects multiple unrelated features. There is no direct replacement for it; if this is a problem for you, please open a GitHub issue and we can come up with an appropriate improvement (perhaps making `nodeEnv` or `includeStackTracesInErrorResponses` available as public readonly fields on `ApolloServer`).
-### Fields on `GraphQLServerContext`
+## Removed features
-The TypeScript type for the argument to the `serverWillStart` plugin hook has been renamed from `GraphQLServiceContext` to `GraphQLServerContext`, for consistency with the hook name.
+Several small features have been removed from Apollo Server 4.
-The `logger` field has been. This field is now available as a public readonly field on the `ApolloServer` object, and `GraphQLServerContext` now provides the `ApolloServer` object in a new field `server`, so `serviceContext.logger` can be replaced with `serverContext.server.logger`.
+### Health checks
-The `schemaHash` field has been removed; see the previous section for details.
+In Apollo Server 3, the health check feature supports a simple `HTTP`-level health check that always returns a 200 status code.
-The `persistedQueries` field has been removed. We did not know of a use case for providing this particular bit of configuration to plugins (other than to a very old version of the operation cache plugin that used it). If having this available in plugins is important for you, please file a GitHub issue.
+Apollo Server 4 no longer supports built-in health checks. We found that running a trivial GraphQL query was a better way of checking the status of your server, because a query ensures your server successfully serves traffic _and_ performs GraphQL operations.
-The `serverlessFramework` field has been removed. The new `startedInBackground` field provides essentially the same information. (In AS3, `serverlessFramework` was true if you were using a subclass of `ApolloServer` designed for a serverless framework, which mostly affected startup error handling. In AS4, there are no subclasses; the API that implements startup error handling in a serverless-friendly way is the new `server.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()` method, and the `startedInBackground` field is true if the server was started with this method instead of with `server.start()` or something that calls `server.start()` such as `startStandaloneServer()`.)
+Every GraphQL server supports a trivial query that requests the [`__typename`](/apollo-server/schema/schema/#the-__typename-field) of the top-level `Query` type. This means every GraphQL server can respond to a `GET` request to a URL, such as:
-### Older Gateway types
+```bash
+https://your.server/?query=%7B__typename%7D
+```
-The `gateway` option to the `ApolloServer` constructor is designed to be used with Apollo Gateway, but can also be used with your own implementation of the gateway interface. Several changes have been made to that interface in Apollo Server 4.
+If you really want to have a health check in your HTTP server that is unrelated to the actual health of the GraphQL execution engine (like Apollo Server 3's health check feature), you can implement that in your web framework by just adding a GET handler that always succeeds.
-In Apollo Server 2, the TypeScript type used for the `gateway` constructor option is called `GraphQLService`. In Apollo Server 3, the TypeScript type is called `GatewayInterface`, but the `apollo-server-core` package continued to export an identical `GraphQLService` type as well.
+### Path parsing
-In Apollo Server 4, the legacy `GraphQLService` type is no longer exported; use `GatewayInterface` instead.
+In Apollo Server 3, several web framework integrations allowed you to "mount" them at a particular URL path and then use the `path` option (which defaults to `/graphql`) to specify that they should actually only process requests at a deeper path.
-In Apollo Server 3, the method `GatewayInterface.load` was declared to return `Promise`, which has a `schema` and an `executor`. In Apollo Server 4, `GraphQLServiceConfig` has been renamed to `GatewayLoadResult`, and it only has an `executor` field; the `onSchemaLoadOrUpdate` hook is sufficient to receive the schema.
+In Apollo Server 4, web framework integrations such as `expressMiddleware` expect that they will be mounted at the appropriate path in the first place using the web framework's routing features. If you used an integration such as `apollo-server-express` and did not configure `path` in AS3, then to maintain the same behavior you should explicitly mount your middleware at `/graphql`. (Note that the batteries-included `apollo-server` package in AS3 (replaced by `startStandaloneServer` in AS4) served at all URLs instead of having the default of `/graphql`.)
-The TypeScript type `GraphQLExecutor` (the type of the `executor` field in the object returned from `GatewayInterface.load`) now returns the `ExecutionResult` type from `graphql-js` rather than the similar `GraphQLExecutionResult` type defined by Apollo Server 3. The types are essentially the same, except that `data` and `extensions` are now `Record`, rather than `Record`.
+### `__resolveObject`
-## Changes to framework integrations
+Apollo Server 4 removes the dependency on `@apollographql/apollo-tooling`, additionally removing the `__resolveObject` pseudo-resolver. The `__resolveObject` function was an undocumented predecessor to
+the [`__resolveReference`](/federation/api/apollo-subgraph/#__resolvereference) method. While we believe `__resolveObject` is a useful feature, it would work better if implemented directly in `graphql-js` rather than in Apollo Server.
-Apollo Server 4 [removes built-in framework integrations](#removed-integrations) and fundamentally changes the Apollo Server API by no longer subclassing `ApolloServer`.
+### `requestAgent` option to `ApolloServerPluginUsageReporting`
-### `expressMiddleware`
+The usage reporting plugin allows you to entirely replace its HTTP client via the `fetcher` option. Additionally, in Apollo Server 3, you could use an older `requestAgent` option, which would be passed to the `fetcher` function via the non-standard `agent` option.
-> If you are using Apollo Server 3's `apollo-server-express` package, you want to use the `expressMiddleware` function from the `@apollo/server` package in Apollo Server 4.
+Apollo Server 4 removes the `requestAgent` operation from `ApolloServerPluginUsageReporting`, and now only passes options that are part of the Fetch API spec to its `fetcher`. If you used `requestAgent` before, you can use the `node-fetch` npm package to override `fetcher` yourself. So if you used `requestAgent` like this:
-In Apollo Server 3, you can use the `apollo-server-express` package to attach Apollo Server to an [`Express` server](https://expressjs.com/).
+```ts
+ApolloServerPluginUsageReporting({ requestAgent })
+```
-Apollo Server 4 introduces the [`expressMiddleware`](https://github.com/apollographql/apollo-server/blob/main/packages/server/src/express/index.ts) function from the `@apollo/server` package, enabling you to attach an `ApolloServer` instance to an [Express](https://expressjs.com/) server without switching packages.
+You can now write:
-The `expressMiddleware` function accepts an `ApolloServer` instance, and as its name implies, you can set up `expressMiddleware` while adding other middleware to your `Express` server. Note that while Apollo Server 3's middleware invisibly defaulted to serving requests on the URL path `/graphql`, you need to specify this explicitly when attaching your middleware to Express in Apollo Server 4.
+```ts
+import fetch from 'node-fetch';
+ApolloServerPluginUsageReporting({
+ fetcher: (url, options) => fetch(url, {
+ ...options,
+ agent: requestAgent,
+ }),
+});
+```
-
-```ts {18}
-import express from 'express';
-import http from 'http';
-import cors from 'cors';
-import { json } from 'body-parser';
-import { ApolloServer, ApolloServerPluginDrainHttpServer } from '@apollo/server';
-import { expressMiddleware } from '@apollo/server/express4';
-import { typeDefs, resolvers } from './schema';
+### Older Gateway types
-// Set up Express
-const app = express();
-const httpServer = http.createServer(app);
+The `gateway` option to the `ApolloServer` constructor is designed to be used with Apollo Gateway, but can also be used with your own implementation of the gateway interface. Several changes have been made to that interface in Apollo Server 4.
-// Set up Apollo Server
-const server = new ApolloServer({
- typeDefs,
- resolvers,
- plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
-});
-await server.start();
+In Apollo Server 2, the TypeScript type used for the `gateway` constructor option is called `GraphQLService`. In Apollo Server 3, the TypeScript type is called `GatewayInterface`, but the `apollo-server-core` package continued to export an identical `GraphQLService` type as well.
-// Pass an ApolloServer instance to the expressMiddleware function.
-app.use('/graphql', cors(), json(), expressMiddleware(server));
-await new Promise((resolve) => httpServer.listen({ port: 4000 }, resolve));
+In Apollo Server 4, the legacy `GraphQLService` type is no longer exported; use `GatewayInterface` instead.
-console.log(`π Server ready at http://localhost:4000`);
-```
+In Apollo Server 3, the method `GatewayInterface.load` was declared to return `Promise`, which has a `schema` and an `executor`. In Apollo Server 4, `GraphQLServiceConfig` has been renamed to `GatewayLoadResult`, and it only has an `executor` field; the `onSchemaLoadOrUpdate` hook is sufficient to receive the schema.
-
+The TypeScript type `GraphQLExecutor` (the type of the `executor` field in the object returned from `GatewayInterface.load`) now returns the `ExecutionResult` type from `graphql-js` rather than the similar `GraphQLExecutionResult` type defined by Apollo Server 3. The types are essentially the same, except that `data` and `extensions` are now `Record`, rather than `Record`.
-Note: the `expressMiddleware` function has no runtime dependency on `express` (or any other package).
+## Changed Features
### New approach to serverless frameworks
@@ -708,164 +670,29 @@ method.
Apollo Server 4's other non-serverless framework integrations expect the developer to await the `server.start()` method, before validating that the server has started by calling `server.assertStarted()`.
-## Changed constructor options
-
-### `debug`
-
-In Apollo Server 3, the `debug` constructor option (which defaulted to true unless the `NODE_ENV` environment variable was set to `production` or `test`) controlled several unrelated aspects of Apollo Server:
-- When `debug` was set to true, stack traces are included on errors in GraphQL responses.
-- If Apollo Server was using its default `logger` implementation, messages sent at the `DEBUG` log level would be printed when `debug` was set to true. (Note that Apollo Server 3's core code wrote almost no messages at the `DEBUG` level, so this only made a difference if your plugins used the provided `logger` to send `DEBUG` messages.)
-- The `debug` flag was made available to plugins on `GraphQLRequestContext` to use as they wish.
+### `context` initialization function
-In Apollo Server 4, the `debug` constructor option has been removed. In its place is a new `includeStackTracesInErrorResponses` option which controls its namesake feature. Like `debug`, this option defaults to true unless the `NODE_ENV` environment variable is set to `production` or `test`. If you set `debug` in Apollo Server 3, you may want to set `includeStackTracesInErrorResponses` to the same value in Apollo Server 4.
+In Apollo Server 3, you could provide an initial [`context`](/apollo-server/data/resolvers#the-context-argument) to your resolvers by adding a `context` initialization function to the `ApolloServer` constructor:
-```ts
-const apolloServerInstance = new ApolloServer({
+```js
+// Apollo Server 3 Constructor
+const server = new ApolloServer({
typeDefs,
resolvers,
- includeStackTracesInErrorResponses: true,
-});
-```
-
-Additionally, if your server did not pass a custom `logger` to `new ApolloServer` and your app or a plugin makes use of `DEBUG`-level log messages, you will need to set the default level yourself. For example, using the same `Logger` implementation that Apollo Server uses by default:
-
-```ts
-import loglevel from 'loglevel';
-
-const logger = loglevel.getLogger('apollo-server');
-logger.setLevel(shouldShowDebugMessages ? loglevel.levels.DEBUG : loglevel.levels.INFO);
-const server = new ApolloServer({
- logger,
- // ...
-});
+ csrfPrevention: true,
+ context: ({ req }) => ({
+ authScope: getScope(req.headers.authorization)
+ })
+}));
```
+In Apollo Server 4, the `context` function is a named argument passed into your web integration function (such as `expressMiddleware` or `startStandaloneServer`). `ApolloServer` itself now has a generic type parameter specifying the type of your context value. The `context` function should return an object, which is then accessible to your [server's resolvers](/apollo-server/data/resolvers/#the-context-argument) and to plugins as the `contextValue` field.
-### `Config` type name
-
-In Apollo Server 4, the TypeScript name of the constructor options object has changed from `Config` to the more aptly named `ApolloServerOptions`.
-
-## Changed Features
-
-The below features have changed in Apollo Server 4.
-
-### `startStandaloneServer`
-
-> If you are using Apollo Server 3's "batteries included" `apollo-server` package, you want to use the `startStandaloneServer` function from the `@apollo/server` package in Apollo Server 4.
-
-Apollo Server 3 has a "batteries-included" `apollo-server` package designed to help developers get started quickly. The "batteries-included" version of `ApolloServer` is less configurable but includes useful defaults to reduce setup time.
-
-In Apollo Server 4, we introduce the `startStandaloneServer` function in the main `@apollo/server` package. The concept of the `startStandaloneServer` function is similar to the "batteries-included" `ApolloServer`, providing you with a streamlined setup experience without offering as much configuration.
-
-Below is the high-level syntax for setting up the `startStandaloneServer` function:
+Below is an example of providing a `context` initialization function to the `startStandaloneServer` function:
-```ts {19}
-import { ApolloServer } from "@apollo/server";
-import { startStandaloneServer } from "@apollo/server/standalone";
-
-// You can optionally create a TS interface to set up types
-// for your context
-interface MyContext {
- token: String;
-}
-
-// Create a new ApolloServer instance, passing in your
-// context's types to ApolloServer's integration function.
-const server = new ApolloServer({
- // The ApolloServer constructor requires two parameters: your schema
- // definition and your set of resolvers.
- typeDefs,
- resolvers,
-});
-
-// startStandaloneServer returns a promise containing the URL where
-// your server is listening
-const { url } = await startStandaloneServer(server, options)
-```
-
-
-
-The `startStandaloneServer` function accepts two arguments, the first is the instance of `ApolloServer` that should begin listening for incoming requests. The second argument is an object for setting up your server's options, which accepts the following properties:
-
-| Name | Description |
-|---|---|
-| `context` | You can optionally provide a [`context` initialization _function_](#context-initialization-function), which should return an object.
|
-| `listen` | These options are passed to the `listen` method of the under-the-hood `http.Server`, similar to the arguments passed to `server.listen()` in Apollo Server 3. Note that this only supports the object form of listen options, such as `{port: 4000}` instead of the number `4000` implying port.
Supported options are listed in the documentation for [net.Server.listen](https://nodejs.org/api/net.html#net_server_listen_options_callback). |
-
-Below is a complete example of setting up the `startStandaloneServer` function:
-
-
-
-```ts
-import { ApolloServer, startStandaloneServer } from "@apollo/server";
-import { typeDefs, resolvers } from "./schema";
-
-interface MyContext {
- token: string;
-}
-
-const apolloServerInstance = new ApolloServer({
- typeDefs,
- resolvers,
-});
-
-const { url } = await startStandaloneServer(apolloServerInstance, {
- // This function is called for every incoming GraphQL request
- context: async ({req, res}) => ({
- token: await getTokenForRequest(req),
- }),
- listen: { port: 4000 }
-});
-
-console.log(`π Server listening at: ${url}`);
-```
-
-
-
-### Default CSRF prevention
-
-Apollo Server 3.7 added a recommended security feature called CSRF prevention, which could be enabled with the constructor option `csrfPrevention: true`. In Apollo Server 4, `true` is the default value. If you want to disable this recommended security feature, pass `csrfPrevention: false`. For more information about CSRF prevention and CORS, see [Configuring CORS](/apollo-server/security/cors).
-
-### Combining packages into `@apollo/server`
-
-Apollo Server 4 takes many previously separate npm packages from Apollo Server 3 and combines them into a single, easy-to-remember `@apollo/server` package.
-
-The following packages have all been incorporated into the `@apollo/server` package:
-- [`apollo-server-core`](https://www.npmjs.com/package/apollo-server-core)
-- [`apollo-server`](https://www.npmjs.com/package/apollo-server) (the previous "batteries-included" package)
-- [`apollo-server-express`](https://www.npmjs.com/package/apollo-server-express)
-- [`apollo-server-errors`](https://www.npmjs.com/package/apollo-server-errors)
-- [`apollo-reporting-protobuf`](https://www.npmjs.com/package/apollo-reporting-protobuf)
-- [`apollo-server-plugin-base`](https://www.npmjs.com/package/apollo-server-plugin-base)
-- [`apollo-server-types`](https://www.npmjs.com/package/apollo-server-types)
-
-A side effect of this change is all actively maintained Apollo packages now start with `@apollo/`. This leaves the `apollo-` namespace open for community integration packages (e.g., `apollo-server-fastify`).
-
-### `context` initialization function
-
-In Apollo Server 3, you could provide an initial [`context`](/apollo-server/data/resolvers#the-context-argument) to your resolvers by adding a `context` initialization function to the `ApolloServer` constructor:
-
-```js
-// Apollo Server 3 Constructor
-const server = new ApolloServer({
- typeDefs,
- resolvers,
- csrfPrevention: true,
- context: ({ req }) => ({
- authScope: getScope(req.headers.authorization)
- })
-}));
-```
-
-In Apollo Server 4, the `context` function is a named argument passed into your web integration function (such as `expressMiddleware` or `startStandaloneServer`). `ApolloServer` itself now has a generic type parameter specifying the type of your context value. The `context` function should return an object, which is then accessible to your [server's resolvers](/apollo-server/data/resolvers/#the-context-argument) and to plugins as the `contextValue` field.
-
-Below is an example of providing a `context` initialization function to the `startStandaloneServer` function:
-
-
-
-```ts {13-15}
+```ts {13-15}
interface MyContext {
token: String;
}
@@ -919,40 +746,6 @@ app.use(
Note that when using `expressMiddleware`, the `req` and `res` objects passed to the `context` function are of type `express.Request` and `express.Response`, but when using `startStandaloneServer`, they are of type `http.IncomingMessage` and `http.ServerResponse`. If you need to use Express-specific properties in your context function, you should use `expressMiddleware`.
-### Improved typing for `context`
-
-In Apollo Server 3, you don't tell TypeScript what type your context value is, so there is no compile-time check that the type returned by your `context` function matches the context value type read by your resolvers and plugins. `ApolloServer` does have a generic parameter, but that parameter is the type of the arguments *passed to* your context function (and is specified by your web integration) rather than your app's context value type.
-
-In Apollo Server 4, you can type your `context` by passing an argument to `ApolloServer`'s integration function. This gives you proper `context` typing throughout, providing you with `context` type inference and enabling you to ensure your `context` object is complete before executing requests. (We no longer need a generic parameter for the type of the arguments to the context function, since the context function is passed directly to the framework-specific middleware function such as `expressMiddleware` which can define the correct type directly.)
-
-You can set up `context` TypeScript typing with `ApolloServer`, like so:
-
-```ts
-// You can optionally create a TS interface to set up types
-// for your context
-interface MyContext {
- token: String
-}
-
-// Create a new ApolloServer instance, passing in your
-// context's types to ApolloServer's integration function.
-const server = new ApolloServer({
- typeDefs,
- resolvers,
- plugins: [
- // Plugins declared to be still work.
- ApolloServerPluginCacheControlDisabled(),
- ],
-});
-
-const { url } = await startStandaloneServer(apolloServerInstance, {
- context: async ({req, res}) => ({
- // You now get proper type inference within your context function!
- token: await getTokenForRequest(req),
- }),
- listen: { port: 4000 }
-});
-```
### `executeOperation` accepts `context` object
@@ -1023,50 +816,6 @@ expect(result.data?.hello).toBe('Hello world!'); // -> true
-### HTTP batching is opt-in
-
-Apollo Server supports [batching HTTP requests](/apollo-server/requests/#batching), enabling a single HTTP request to execute multiple GraphQL operations. In Apollo Server 3, support for HTTP batching was on by default.
-
-In Apollo Server 4, you must explicitly enable this feature by passing `allowBatchedHttpRequests: true` to the `ApolloServer` constructor.
-
-Not all GraphQL clients support HTTP batching, and batched requests will not support incremental delivery when Apollo Server implements that feature. HTTP batching can help performance by sharing a `context` object across operations, but it can make it harder to understand the amount of work any given request does.
-
-### `@apollo/utils.fetcher` for TypeScript typing
-
-In Apollo Server 3, the `apollo-server-env` package primarily provides TypeScript typings and polyfills for the `fetch` and `URL` APIs.
-
-Apollo Server 4 introduces `@apollo/utils.fetcher`, which defines a minimal fetch API (`Fetcher`) that provides Fetch API TypeScript typings.
-
-With this change, we are also removing the `requestAgent` option from the [usage reporting plugin](/apollo-server/api/plugin/usage-reporting/), because `requestAgent` is specific to the `node-fetch` implementation of the Fetch API. If you used `requestAgent` like this:
-```ts
- ApolloServerPluginUsageReporting({ requestAgent })
-```
-
-You can now write:
-```ts
- import fetch from 'node-fetch';
-
- ApolloServerPluginUsageReporting({
- fetcher: (url, options) => fetch(url, {
- ...options,
- agent: requestAgent,
- }),
- });
-```
-
-### Default cache is bounded
-
-Each Apollo Server has a cache that is used for several features, such as APQs, the response cache plugin, and `RESTDataSource`. This cache can be in-memory or use a server such as Redis, and is configured with the `cache` constructor option.
-
-In Apollo Server 3, the default cache is an unbounded in-memory cache. This is vulnerable to denial of service attacks via memory exhaustion, and we recommend that users do not use this default cache.
-
-In Apollo Server 4, the default cache is a bounded in-memory cache backend (which _is safe_ for production use). This is equivalent to passing `cache: 'bounded'` in Apollo Server 3.9 or newer.
-
-If you want to customize the cache Apollo Server uses, Apollo provides two wrapper packages to help with this process:
-* [`@apollo/utils.keyvadapter`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyvAdapter) - provides a [`KeyvAdapter`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyvAdapter#keyvadapter-class) wrapper class to use alongside the [`keyv`](https://www.npmjs.com/package/keyv) package.
-* [`@apollo/utils.keyvaluecache`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache) - provides both the [`KeyValueCache`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache#keyvaluecache-interface) TypeScript interface and a [`InMemoryLRUCache`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache#inmemorylrucache) class (a wrapper around the `lru-cache` package).
-
-For examples of using both `KeyvAdapter` and `InMemoryLRUCache`, see [Configuring external caching](/apollo-server/performance/cache-backends#configuring-external-caching).
### Top-level error handling changes
@@ -1086,7 +835,7 @@ Apollo Server 4 also introduces new plugin hooks `startupDidFail`, `contextCreat
In Apollo Server 4, if either the `resolveOperation` or `execute` function throws an error, that error is rendered with the HTTP status code 500 (rather than 400). Note that the `execute` function commonly returns a non-empty list of errors, rather than throwing an explicit error.
-### `variables` and `extensions` fields
+### Doubly-escaped `variables` and `extensions` in requests
Apollo Server 3 and 4 both accept `POST` requests with a JSON body.
@@ -1111,32 +860,6 @@ Whereas this query would be invalid:
}
```
-### Local landing page defaults to Embedded Apollo Sandbox
-
-In Apollo Server 3, the default development landing page is a splash page containing a link to Apollo Sandbox hosted at https://studio.apollographql.com/. This hosted Sandbox only works if your server's CORS configuration allows the origin https://studio.apollographql.com/ to talk to it. You can also configure `ApolloServerPluginLandingPageLocalDefault` with `embed: true` to embed Apollo Sandbox directly in the landing page; in this mode, Sandbox is able to make same-origin requests to your server and no CORS configuration is necessary.
-
-In Apollo Server 4, the default development landing page is the embedded Apollo Sandbox. Note that nothing changes about the default production landing page.
-
-To restore the splash page, write:
-
-
-
-```ts
-import { ApolloServer } from '@apollo/server';
-import { ApolloServerPluginLandingPageLocalDefault, ApolloServerPluginLandingPageProductionDefault }
- from '@apollo/server/plugin/landingPage/default';
-
-new ApolloServer({
- // ...
- plugins: [
- process.env.NODE_ENV === 'production'
- ? ApolloServerPluginLandingPageProductionDefault()
- : ApolloServerPluginLandingPageLocalDefault({ embed: false })
- ],
-});
-```
-
-
### Warning for servers without draining
@@ -1157,14 +880,41 @@ export type CacheScope = 'PUBLIC' | 'PRIVATE';
You can no longer type `CacheScope.Public` or `CacheScope.Private`. Instead, just use the string `'PUBLIC'` or `'PRIVATE'`. Values defined as `CacheScope` will only accept those two values, so typos will still be caught at compile time.
-### `GraphQLRequest`
-Apollo Server 4 refactors the `GraphQLRequest` object (e.g., `requestContext.request`). Specifically, its `http` field is now a new `HTTPGraphQLRequest` type instead of a type based on the Fetch API `Request` object. This object does not contain the URL path, and its `headers` field is a `Map` (with lower-case keys) rather than a Fetch API `Headers` object.
+## Plugin API changes
+
+### Fields on `GraphQLRequestContext`
+
+Most plugin API hooks take a `GraphQLRequestContext` object as their first argument. There are several changes to this object.
+
+The `context` field has been renamed to `contextValue`, for consistency with the `graphql-js` API and to differentiate from the `context` option to integration functions, which is a *function* returning a context value.
+The `logger` and `cache` fields have been removed. These fields are now available as public readonly fields on the `ApolloServer` object, and `GraphQLRequestContext` now provides the `ApolloServer` object in a new field `server`, so `requestContext.logger` and `requestContext.cache` can be replaced with `requestContext.server.logger` and `requestContext.server.cache` respectively.
+
+The `schemaHash` field has been removed. This field was a not particularly stable hash of a JSON encoding of the result of running the GraphQL introspection query against the schema. It was not guaranteed to change when the schema changed (eg, it is not affected by changes to schema directive applications). If you need a hash of the schema, you can hash the output of applying the `graphql-js` `printSchema` function to the `schema` field (perhaps with some sort of memoization).
+
+The `debug` field has been removed, because `ApolloServer` no longer has a vague `debug` option that affects multiple unrelated features. There is no direct replacement for it; if this is a problem for you, please open a GitHub issue and we can come up with an appropriate improvement (perhaps making `nodeEnv` or `includeStackTracesInErrorResponses` available as public readonly fields on `ApolloServer`).
+
+
+### Fields on `GraphQLServerContext`
+
+The TypeScript type for the argument to the `serverWillStart` plugin hook has been renamed from `GraphQLServiceContext` to `GraphQLServerContext`, for consistency with the hook name.
+
+The `logger` field has been. This field is now available as a public readonly field on the `ApolloServer` object, and `GraphQLServerContext` now provides the `ApolloServer` object in a new field `server`, so `serviceContext.logger` can be replaced with `serverContext.server.logger`.
+
+The `schemaHash` field has been removed; see the previous section for details.
+
+The `persistedQueries` field has been removed. We did not know of a use case for providing this particular bit of configuration to plugins (other than to a very old version of the operation cache plugin that used it). If having this available in plugins is important for you, please file a GitHub issue.
+
+The `serverlessFramework` field has been removed. The new `startedInBackground` field provides essentially the same information. (In AS3, `serverlessFramework` was true if you were using a subclass of `ApolloServer` designed for a serverless framework, which mostly affected startup error handling. In AS4, there are no subclasses; the API that implements startup error handling in a serverless-friendly way is the new `server.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()` method, and the `startedInBackground` field is true if the server was started with this method instead of with `server.start()` or something that calls `server.start()` such as `startStandaloneServer()`.)
+
+### `GraphQLRequest`
+
+Apollo Server 4 refactors the `GraphQLRequest` object. (This object is available to plugins as `requestContext.request`, and is the argument to `server.executeOperation`.) Specifically, its `http` field is now a new `HTTPGraphQLRequest` type instead of a type based on the Fetch API `Request` object. This object does not contain the URL path, and its `headers` field is a `Map` (with lower-case keys) rather than a Fetch API `Headers` object.
### `GraphQLResponse`
-Apollo Server 4 refactors the [`GraphQLResponse` object](https://github.com/apollographql/apollo-server/blob/version-4/packages/server/src/externalTypes/graphql.ts#L25) (e.g., `requestContext.response`). The `data`, `errors`, and `extensions` fields are now nested within an object returned by the `result` field:
+Apollo Server 4 refactors the [`GraphQLResponse` object](https://github.com/apollographql/apollo-server/blob/version-4/packages/server/src/externalTypes/graphql.ts#L25). (This object is available to plugins as `requestContext.response`, and is returned by `server.executeOperation`.) The `data`, `errors`, and `extensions` fields are now nested within an object returned by the `result` field:
```ts disableCopy
export interface GraphQLResponse {
@@ -1175,17 +925,147 @@ export interface GraphQLResponse {
}
```
-
Additionally, the `data` and `extensions` fields are both type `Record`, rather than `Record`.
`http.headers` is now a `Map` (with lower-case keys) rather than a Fetch API `Headers` object.
Note: we plan to implement experimental support for incremental delivery (`@defer`/`@stream`) before the v4.0.0 release, and we expect that this will change the structure of `GraphQLResponse` further.
-### `@apollo/server-plugin-operation-registry`
-The plugin `apollo-server-plugin-operation-registry` has been renamed `@apollo/server-plugin-operation-registry`.
-## Plugin semantics changes
+### Changes to plugin semantics
+
+`requestDidStart` hooks are called in parallel rather than in series.
+
+Errors thrown by many plugin hooks are handled more consistently by wrapping the error in an "Unexpected error handling request" error and invoking the new `unexpectedErrorProcessingRequest` plugin hook.
+
+## Changes to defaults
+
+Several recommended features were introduced to Apollo Server 3 after the initial v3.0.0 release but were left off by default for backwards compatibility. In Apollo Server 4, the recommended behavior is the default. In each case, you can still configure your server to match the default behavior from Apollo Server 3 if required for compatibility.
+
+
+### CSRF prevention is on by default
+
+Apollo Server 3.7 added a recommended security feature called CSRF prevention, which could be enabled with the constructor option `csrfPrevention: true`. In Apollo Server 4, `true` is the default value. If you want to disable this recommended security feature, pass `csrfPrevention: false`. For more information about CSRF prevention and CORS, see [Configuring CORS](/apollo-server/security/cors).
+
+
+### HTTP batching is off by default
+
+Apollo Server supports [batching HTTP requests](/apollo-server/requests/#batching), enabling a single HTTP request to execute multiple GraphQL operations. In Apollo Server 3, support for HTTP batching was on by default.
+
+In Apollo Server 4, you must explicitly enable this feature by passing `allowBatchedHttpRequests: true` to the `ApolloServer` constructor.
+
+Not all GraphQL clients support HTTP batching, and batched requests will not support incremental delivery when Apollo Server implements that feature. HTTP batching can help performance by sharing a `context` object across operations, but it can make it harder to understand the amount of work any given request does.
+
+
+### Default cache is bounded
+
+Each Apollo Server has a cache that is used for several features, such as APQs, the response cache plugin, and `RESTDataSource`. This cache can be in-memory or use a server such as Redis, and is configured with the `cache` constructor option.
+
+In Apollo Server 3, the default cache is an unbounded in-memory cache. This is vulnerable to denial of service attacks via memory exhaustion, and we recommend that users do not use this default cache.
+
+In Apollo Server 4, the default cache is a bounded in-memory cache backend (which _is safe_ for production use). This is equivalent to passing `cache: 'bounded'` in Apollo Server 3.9 or newer.
+
+If you want to customize the cache Apollo Server uses, Apollo provides two wrapper packages to help with this process:
+* [`@apollo/utils.keyvadapter`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyvAdapter) - provides a [`KeyvAdapter`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyvAdapter#keyvadapter-class) wrapper class to use alongside the [`keyv`](https://www.npmjs.com/package/keyv) package.
+* [`@apollo/utils.keyvaluecache`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache) - provides both the [`KeyValueCache`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache#keyvaluecache-interface) TypeScript interface and a [`InMemoryLRUCache`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyValueCache#inmemorylrucache) class (a wrapper around the `lru-cache` package).
+
+For examples of using both `KeyvAdapter` and `InMemoryLRUCache`, see [Configuring external caching](/apollo-server/performance/cache-backends#configuring-external-caching).
+
+If you really want your server to use an unbounded in-memory cache like in AS3 (which may make your server vulnerable to memory exhaustion attacks), you can use the default `Keyv` implementation with no arguments:
+
+
+
+```ts
+import { ApolloServer } from '@apollo/server';
+import { KeyvAdapter } from '@apollo/utils.keyvadapter';
+import Keyv from 'keyv';
+
+new ApolloServer({
+ // DANGEROUS: Match the unsafe default AS3 behavior with an
+ // unbounded in-memory cache.
+ cache: new KeyvAdapter(new Keyv()),
+ // ...
+});
+
+```
+
+
+
+
+### Local landing page defaults to Embedded Apollo Sandbox
+
+In Apollo Server 3, the default development landing page is a splash page containing a link to Apollo Sandbox hosted at https://studio.apollographql.com/. This hosted Sandbox only works if your server's CORS configuration allows the origin https://studio.apollographql.com/ to talk to it. You can also configure `ApolloServerPluginLandingPageLocalDefault` with `embed: true` to embed Apollo Sandbox directly in the landing page; in this mode, Sandbox is able to make same-origin requests to your server and no CORS configuration is necessary.
+
+In Apollo Server 4, the default development landing page is the *embedded* Apollo Sandbox. Note that nothing changes about the default production landing page.
+
+To continue to show a splash page like in Apollo Server 3, write:
+
+
+
+```ts
+import { ApolloServer } from '@apollo/server';
+import { ApolloServerPluginLandingPageLocalDefault, ApolloServerPluginLandingPageProductionDefault }
+ from '@apollo/server/plugin/landingPage/default';
+
+new ApolloServer({
+ // ...
+ plugins: [
+ process.env.NODE_ENV === 'production'
+ ? ApolloServerPluginLandingPageProductionDefault()
+ : ApolloServerPluginLandingPageLocalDefault({ embed: false })
+ ],
+});
+```
+
+
+
+## TypeScript-only changes
+
+Some changes only affect TypeScript typings, not runtime behavior. For example, we have changed some of the names of TypeScript interfaces to be more clear, and we've changed what packages we use to define other interfaces. (Changes that affect more than just typings (like renaming `GraphQLServiceContext` and `GraphQLServiceConfig`) are described elsewhere.)
+
+### `Config` type name
+
+In Apollo Server 4, the TypeScript name of the constructor options object has changed from `Config` to the more aptly named `ApolloServerOptions`.
+
+### Improved typing for `context`
+
+In Apollo Server 3, you don't tell TypeScript what type your context value is, so there is no compile-time check that the type returned by your `context` function matches the context value type read by your resolvers and plugins. `ApolloServer` does have a generic parameter, but that parameter is the type of the arguments *passed to* your context function (and is specified by your web integration) rather than your app's context value type.
+
+In Apollo Server 4, you can type your `context` by passing an argument to `ApolloServer`'s integration function. This gives you proper `context` typing throughout, providing you with `context` type inference and enabling you to ensure your `context` object is complete before executing requests. (We no longer need a generic parameter for the type of the arguments to the context function, since the context function is passed directly to the framework-specific middleware function such as `expressMiddleware` which can define the correct type directly.)
+
+You can set up `context` TypeScript typing with `ApolloServer`, like so:
+
+```ts
+// You can optionally create a TS interface to set up types
+// for your context
+interface MyContext {
+ token: String
+}
+
+// Create a new ApolloServer instance, passing in your
+// context's types to ApolloServer's integration function.
+const server = new ApolloServer({
+ typeDefs,
+ resolvers,
+ plugins: [
+ // Plugins declared to be still work.
+ ApolloServerPluginCacheControlDisabled(),
+ ],
+});
+
+const { url } = await startStandaloneServer(apolloServerInstance, {
+ context: async ({req, res}) => ({
+ // You now get proper type inference within your context function!
+ token: await getTokenForRequest(req),
+ }),
+ listen: { port: 4000 }
+});
+```
+
+### `@apollo/utils.fetcher` replaces `apollo-server-env`
+
+In Apollo Server 3, the `apollo-server-env` package primarily provides TypeScript typings and polyfills for the `fetch` and `URL` APIs.
+
+Apollo Server 4 introduces `@apollo/utils.fetcher`, which defines a minimal fetch API (`Fetcher`) that provides Fetch API TypeScript typings. It is similar to `apollo-server-env` but has a clearer name and only supports argument structures that are likely to be compatible across many implementations of the Fetch API. (Specifically, it does not allow you to pass `Request` or `Headers` objects to `fetch`, because libraries often only know how to recognize their own implementations of these interfaces.)
-requestDidStart hooks are called in parallel rather than in series.
From 59bbde4e3251c079586bd8c3df06f406cfd11ba3 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Wed, 20 Jul 2022 12:42:18 -0700
Subject: [PATCH 05/19] Apply suggestions from code review
Co-authored-by: Rose M Koron <32436232+rkoron007@users.noreply.github.com>
---
docs/source/migration.mdx | 30 ++++++++++++++++--------------
1 file changed, 16 insertions(+), 14 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index f718d5dc233..cdcf368782b 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -24,9 +24,9 @@ TODO: Maybe rename section?
Apollo Server 3 ships with a fixed set of integrations with a variety of web frameworks and serverless environments, but does not provided a supported mechanism for integrating with additional frameworks. In Apollo Server 3, changes to framework integrations could only be released with lockstep versioning with Apollo Server itself, which has made it challenging to support multiple major versions of frameworks or make other integration-specific changes. Each of these integrations are released in a separate package, such as `apollo-server-express` or `apollo-server-lambda`. The core logic is implemented in a variety of packages, most notably `apollo-server-core`. This package defines an `ApolloServer` "base" class, and each integration package exports a subclass with the same name with slightly different APIs. Additionally, the `apollo-server` package is a "batteries-included" package which wraps `apollo-server-express` and provides a full HTTP server without the need to learn about a particular web framework, while providing minimal opportunities for HTTP-level customization.
-Apollo Server 4 takes a different approach. The Apollo Server core team no longer maintains most of these integrations. Instead, Apollo Server now has a simple stable web framework integration API (including explicit support for serverless framework life cycles). The new `@apollo/server` package contains the `ApolloServer` class, as well as an Express 4 integration (similar to AS3's `apollo-server-express` package) and a standalone server (similar to AS3's `apollo-server` package). There are no subclasses in AS4: there is a single `ApolloServer` class with a single API, and integrations use that API.
+Apollo Server 4 takes a different approach to integrations. Apollo Server 4 has a stable web framework integration API, which includes explicit support for serverless framework life cycles. The new `@apollo/server` package contains the `ApolloServer` class, an [Express 4 integration](#migrating-from-apollo-server-express) (similar to AS3's `apollo-server-express` package), and a [standalone server](#migrating-from-apollo-server) (similar to AS3's `apollo-server` package). There are no subclasses in AS4; there is a single `ApolloServer` class with a single API that all integrations use.
-The Apollo Server core team no longer maintains the other integrations. We will work with the broader open source community, allowing users of other web frameworks to make the best choices for their framework's integrations rather than expecting the core team to be intimately familiar with the best practices of a dozen different projects. Our hope is that there will exist upgrade paths for all of AS3's integrations by the time we release v4.0.0; if you'd like to help, we have [an issue calling for maintainers for each integration](https://github.com/apollographql/apollo-server/labels/integration-collaborators).
+In Apollo Server 3, the Apollo Server core team is responsible for maintaining all integration packages. With Apollo Server 4, the AS core team will stop directly maintaining most integration packages. We will instead work with the broader open source community to maintain Apollo Server integrations, enabling those who regularly use different web frameworks to make the best choices for their framework's integration. If you'd like to help maintain an integration, please [see this issue calling for integration maintainers](https://github.com/apollographql/apollo-server/labels/integration-collaborators).
For those migrating from Apollo Server 3 to Apollo Server 4, use the below flowchart to see your migration path:
@@ -40,7 +40,7 @@ graph TB;
class useStandAlone,useExpressMiddleware secondary;
```
-If you are currently using the `apollo-server` package, you should use the [`startStandaloneServer`](#startstandaloneserver-function) function. If you are using the `apollo-server-express` package, you should use the [`expressMiddleware`](#expressmiddleware) function. These functions, as well as the `ApolloServer` class, are exported from the new `@apollo/server` package.
+If you are currently using the `apollo-server` package, you should use the [`startStandaloneServer`](#migrating-from-apollo-server) function. If you are using the `apollo-server-express` package, you should use the [`expressMiddleware`](#migrating-from-apollo-server-express) function. These functions and the `ApolloServer` class are all exported from the [`@apollo/server` package](https://www.npmjs.com/package/@apollo/server).
If you are using any other Apollo Server 3 framework integration package, you canβt upgrade during the AS4 alpha release _yet_. Please help us by [building new integrations](/building-integrations) or [discussing how to maintain existing integrations](https://github.com/apollographql/apollo-server/labels/integration-collaborators) to ensure there is an Apollo Server 4 integration for your favorite framework.
@@ -107,11 +107,13 @@ async function startApolloServer() {
### Migrating from `apollo-server-express`
-If you used the `apollo-server-express` package in Apollo Server 3, you'll want to use the `expressMiddleware` function in Apollo Server 4 instead of the `applyMiddleware` method. The changes include:
+If you used the `apollo-server-express` package in Apollo Server 3, you'll use the `expressMiddleware` function in Apollo Server 4 (instead of using `applyMiddleware`).
-- Installing `@apollo/server`, `cors`, and `body-parser` instead of `apollo-server-express` and `apollo-server-core`
-- Importing symbols from `@apollo/server` instead of `apollo-server-express` and `apollo-server-core`
-- Explicitly adding `cors` and `bodyParser.json()
+To migrate from AS3's `apollo-server-express` package to using the `expressMiddleware` function, you'll need to do the following:
+- Install the `@apollo/server`, `cors`, and `body-parser` packages.
+- Import symbols from `@apollo/server` (instead of `apollo-server-express` and `apollo-server-core`).
+- Add `cors` and `bodyParser.json()` to your server setup.
+- Remove the Apollo Server 3 `apollo-server-express` and `apollo-server-core` packages.
Note that by default, `apollo-server-express` in AS3 would only actually respond to operations on `/graphql`, so we explicitly mount `expressMiddleware` at that path in AS4.
@@ -188,9 +190,9 @@ async function startApolloServer() {
-### Integrations no longer part of core
+### Removed integrations
-The Apollo Server core team is no longer maintaining the following integration packages in Apollo Server 4. We are [looking for collaborators](https://github.com/apollographql/apollo-server/labels/integration-collaborators) who actively use these platforms to maintain AS4-compatible integration packages and will add links here once they exist.
+The Apollo Server core team no longer maintains the following integration packages in Apollo Server 4. We are [looking for collaborators](https://github.com/apollographql/apollo-server/labels/integration-collaborators) who actively use these platforms to maintain AS4-compatible integration packages.
Apollo Server 4 removes the below integration packages:
* [`apollo-server-fastify`](https://www.npmjs.com/package/apollo-server-fastify)
@@ -202,9 +204,9 @@ Apollo Server 4 removes the below integration packages:
* [`apollo-server-cloudflare`](https://www.npmjs.com/package/apollo-server-cloudflare)
* [`apollo-server-azure-functions`](https://www.npmjs.com/package/apollo-server-azure-functions)
-Additionally, in Apollo Server 3 the `apollo-server-express` package supported both Express and its older predecessor [Connect](https://github.com/senchalabs/connect) using the same code. In Apollo Server 4, `expressMiddleware` no longer supports Connect. An interested developer could [build a Connect-specific middleware](/integrations/building-integrations) using the Apollo Server 4 API. A PR to this migration guide is welcome if someone does this!
+In Apollo Server 3, the `apollo-server-express` package supported both Express and its older predecessor [Connect](https://github.com/senchalabs/connect). In Apollo Server 4, `expressMiddleware` no longer supports Connect. An interested developer could [build a Connect-specific middleware](/integrations/building-integrations), and a PR to this migration guide is welcome if someone does this!
-### Other packages merged into `@apollo/server`
+### Packages merged into `@apollo/server`
As described above, the functionality provided by the `apollo-server-core`, `apollo-server`, and `apollo-server-express` packages in AS3 has been combined into the single `@apollo/server` package in AS4.
@@ -214,7 +216,7 @@ But wait: there's more! The following packages have *also* been combined into `@
- [`apollo-server-types`](https://www.npmjs.com/package/apollo-server-types)
-### Other renamed packages
+### Renamed packages
The `apollo-server-plugin-response-cache` and `apollo-server-plugin-operation-registry` plugin packages have been renamed to `@apollo/server-plugin-response-cache` and `@apollo/server-plugin-operation-registry` respectively.
@@ -251,9 +253,9 @@ The following `ApolloServer` constructor options have been removed in favor of o
### `dataSources`
-In Apollo Server 3, the top-level [`dataSources` constructor option](/apollo-server/data/data-sources#adding-data-sources-to-apollo-server) essentially added a post-processing step to your app's context function which created `DataSource` subclasses and added them to a `dataSources` field on your [`context`](/apollo-server/data/resolvers/#the-context-argument) object. This meant that the type returned by your `context` function and the context type received by resolvers and plugins were actually different. This also obfuscated the fact that the `DataSource` objects were created once per request like the rest of the context object.
+In Apollo Server 3, the top-level [`dataSources` constructor option](/apollo-server/data/data-sources#adding-data-sources-to-apollo-server) essentially adds a post-processing step to your app's context function, creating `DataSource` subclasses and adding them to a `dataSources` field on your [`context`](/apollo-server/data/resolvers/#the-context-argument) object. This means the TypeScript types returned by the `context` function and the `context` types received in the resolvers and plugins are _different_. Additionally, this design obfuscates that `DataSource` objects are created once per request (i.e., like the rest of the context object).
-In Apollo Server 4, we have removed the `dataSources` constructor option. You can treat `DataSources` like any other part of your `context` object.
+In Apollo Server 4, we have removed the `dataSources` constructor option. You can treat `DataSources` like any other part of your `context` object:
TODO: rewrite as before and after (and fully review)
From 875bb2ce0797f0b170c3d2034a20ae36f7ab0f73 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Wed, 20 Jul 2022 13:28:24 -0700
Subject: [PATCH 06/19] migration: result of auditing the change in exported
API
---
docs/source/migration.mdx | 39 ++++++++++++++++++++++++++++++++++-----
1 file changed, 34 insertions(+), 5 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index cdcf368782b..43b2f4ebe4f 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -107,7 +107,7 @@ async function startApolloServer() {
### Migrating from `apollo-server-express`
-If you used the `apollo-server-express` package in Apollo Server 3, you'll use the `expressMiddleware` function in Apollo Server 4 (instead of using `applyMiddleware`).
+If you used the `apollo-server-express` package in Apollo Server 3, you'll use the `expressMiddleware` function in Apollo Server 4 (instead of using `applyMiddleware`).
To migrate from AS3's `apollo-server-express` package to using the `expressMiddleware` function, you'll need to do the following:
- Install the `@apollo/server`, `cors`, and `body-parser` packages.
@@ -192,7 +192,7 @@ async function startApolloServer() {
### Removed integrations
-The Apollo Server core team no longer maintains the following integration packages in Apollo Server 4. We are [looking for collaborators](https://github.com/apollographql/apollo-server/labels/integration-collaborators) who actively use these platforms to maintain AS4-compatible integration packages.
+The Apollo Server core team no longer maintains the following integration packages in Apollo Server 4. We are [looking for collaborators](https://github.com/apollographql/apollo-server/labels/integration-collaborators) who actively use these platforms to maintain AS4-compatible integration packages.
Apollo Server 4 removes the below integration packages:
* [`apollo-server-fastify`](https://www.npmjs.com/package/apollo-server-fastify)
@@ -216,6 +216,10 @@ But wait: there's more! The following packages have *also* been combined into `@
- [`apollo-server-types`](https://www.npmjs.com/package/apollo-server-types)
+### Plugins are now in `@apollo/server`
+
+TODO: describe that plugins are now in `@apollo/server` at deep imports
+
### Renamed packages
The `apollo-server-plugin-response-cache` and `apollo-server-plugin-operation-registry` plugin packages have been renamed to `@apollo/server-plugin-response-cache` and `@apollo/server-plugin-operation-registry` respectively.
@@ -488,6 +492,8 @@ new ApolloServer({
})
```
+The corresponding `GraphQLSchemaModule` TypeScript type is no longer exported.
+
### `mocks` and `mockEntireSchema`
In Apollo Server 3, the `mocks` and `mockEntireSchema` constructor options enabled Apollo Server to return simulated data for GraphQL operations based on your server's schema.
@@ -606,6 +612,12 @@ In Apollo Server 3, several web framework integrations allowed you to "mount" th
In Apollo Server 4, web framework integrations such as `expressMiddleware` expect that they will be mounted at the appropriate path in the first place using the web framework's routing features. If you used an integration such as `apollo-server-express` and did not configure `path` in AS3, then to maintain the same behavior you should explicitly mount your middleware at `/graphql`. (Note that the batteries-included `apollo-server` package in AS3 (replaced by `startStandaloneServer` in AS4) served at all URLs instead of having the default of `/graphql`.)
+
+### `gql` GraphQL tag
+
+TODO: explain that `gql` probably isn't even that important for servers but can be gotten directly from `graphql-tag`
+
+
### `__resolveObject`
Apollo Server 4 removes the dependency on `@apollographql/apollo-tooling`, additionally removing the `__resolveObject` pseudo-resolver. The `__resolveObject` function was an undocumented predecessor to
@@ -1026,9 +1038,6 @@ new ApolloServer({
Some changes only affect TypeScript typings, not runtime behavior. For example, we have changed some of the names of TypeScript interfaces to be more clear, and we've changed what packages we use to define other interfaces. (Changes that affect more than just typings (like renaming `GraphQLServiceContext` and `GraphQLServiceConfig`) are described elsewhere.)
-### `Config` type name
-
-In Apollo Server 4, the TypeScript name of the constructor options object has changed from `Config` to the more aptly named `ApolloServerOptions`.
### Improved typing for `context`
@@ -1071,3 +1080,23 @@ In Apollo Server 3, the `apollo-server-env` package primarily provides TypeScrip
Apollo Server 4 introduces `@apollo/utils.fetcher`, which defines a minimal fetch API (`Fetcher`) that provides Fetch API TypeScript typings. It is similar to `apollo-server-env` but has a clearer name and only supports argument structures that are likely to be compatible across many implementations of the Fetch API. (Specifically, it does not allow you to pass `Request` or `Headers` objects to `fetch`, because libraries often only know how to recognize their own implementations of these interfaces.)
+
+### Renamed types
+
+This section lists TypeScript-only types (such as interfaces, but not classes) whose name has been changed in Apollo Server 4 (not including those mentioned elsewhere in this guide).
+
+The name of the constructor options type has changed from `Config` to the more aptly named `ApolloServerOptions`. Some integration packages exported their own version of this type such as `ApolloServerExpressConfig`; these are no longer necessary because there is only one `ApolloServer` type with only one constructor in AS4.
+
+Two types in `apollo-server-express` now have more explicit names exported from `@apollo/server/express4`. `GetMiddlewareOptions` is now `ExpressMiddlewareOptions`, and `ExpressContext` is now `ExpressContextFunctionArgument`.
+
+### Removed types
+
+This section lists TypeScript-only types (such as interfaces, but not classes) which have been removed in Apollo Server 4 (not including those mentioned elsewhere in this guide).
+
+`GraphQLOptions` was an internal type used to create integrations which was only exported for technical reasons. It no longer exists.
+
+`ServerRegistration` was related to `applyMiddleware`, which no longer exists.
+
+`CorsOptions` and `OptionsJson` were re-exported from the `cors` and `body-parser` packages. Because Apollo Server 4 no longer handles these tasks for you, these types are no longer re-exported.
+
+`ServerInfo` (returned from `server.listen()` in `apollo-server`) no longer exists. `startStandaloneServer` returns a simpler data structure that currently has no type name.
From 0320f2e1771cbde69ff15ccccc8d89d7ae45051b Mon Sep 17 00:00:00 2001
From: Ivan Goncharov
Date: Mon, 18 Jul 2022 15:55:47 +0300
Subject: [PATCH 07/19] migration: Add description of changes from #6355
---
docs/source/migration.mdx | 60 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 1 deletion(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index 43b2f4ebe4f..23bb775d077 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -831,7 +831,65 @@ expect(result.data?.hello).toBe('Hello world!'); // -> true
-### Top-level error handling changes
+### Error handling changes
+
+#### ApolloError removal
+
+`ApolloError` and `toApolloError` were removed in favor of using `GraphQLError` directly.
+`GraphQLError` is exported by the `graphql` package, and you can use it in your code:
+```
+import { GraphQLError } from 'graphql';
+
+// ...
+throw new GraphQLError(message, {
+ extensions: { code: 'YOUR_ERROR_CODE' },
+});
+```
+
+Note: If you previously passed the optional `code` argument as such:
+```
+throw new ApolloError(message, 'YOUR_ERROR_CODE');
+```
+You now need to pass it inside `extensions`. See above example.
+
+#### Changes to `formatError` hook
+
+Apollo Server 3 supported the `formatError` hook with the following signature:
+```
+(error: GraphQLError) => GraphQLFormattedError
+```
+
+In Apollo Server 4, it became:
+```
+(formattedError: GraphQLFormattedError, error: unknown) => GraphQLFormattedError
+```
+Where `formattedError` is instance `GraphQLError` serialized as plain-old object according to [GraphQL specification](https://spec.graphql.org/draft/#sec-Errors).
+If you need some field from the error that isn't part of `GraphQLFormattedError`, you can access the value that was thrown initially as an `error` argument.
+
+So now you can format errors as such:
+```
+ formatError: (formattedError, error) => {
+ // Don't give the specific errors to the client.
+ if (error instanceof CustomDBError) {
+ return { message: 'Internal server error' };
+ }
+
+ // Strip `Validation: ` prefix and use `extensions.code` instead
+ if (formattedError.message.startsWith('Validation:')) {
+ return {
+ ...formattedError,
+ message: formattedError.message.replace(/^Validation: /, ''),
+ extensions: { ...formattedError?.extensions, code: 'VALIDATION' },
+ };
+ }
+
+ // Otherwise, return the original error. The error can also
+ // be manipulated in other ways, as long as it's returned.
+ return formattedError;
+ },
+```
+
+#### Top-level error handling changes
Apollo Server 3 returns specific errors relating to GraphQL operations over HTTP/JSON as `text/plain` error messages.
From 5232d8f54048a0b9cc0702bf8a624ac65e5c43fc Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Wed, 20 Jul 2022 15:06:27 -0700
Subject: [PATCH 08/19] Reorganize error handling changes
---
docs/source/migration.mdx | 94 ++++++++++++++++++++++++++++-----------
1 file changed, 67 insertions(+), 27 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index 23bb775d077..2412bb65a79 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -618,6 +618,67 @@ In Apollo Server 4, web framework integrations such as `expressMiddleware` expec
TODO: explain that `gql` probably isn't even that important for servers but can be gotten directly from `graphql-tag`
+### `ApolloError`
+
+`ApolloError` and `toApolloError` were removed in favor of using `GraphQLError` directly.
+`GraphQLError` is exported by the `graphql` package, and you can use it in your code:
+```
+import { GraphQLError } from 'graphql';
+
+// ...
+throw new GraphQLError(message, {
+ extensions: { code: 'YOUR_ERROR_CODE' },
+});
+```
+
+Note: If you previously passed the optional `code` argument as such:
+```
+throw new ApolloError(message, 'YOUR_ERROR_CODE');
+```
+You now need to pass it inside `extensions`. See above example.
+
+### Built-in error classes
+
+Apollo Server 3 exports a number of specific error classes. Some of them (`SyntaxError`, `ValidationError`, and `UserInputError`) are produced by Apollo Server's own code. Others (`ForbiddenError` and `AuthenticationError`) are provided for users to use in their apps. These are subclasses of the `ApolloError` class.
+
+In Apollo Server 4 (as described above) `ApolloError` no longer exists, and we no longer export the specific error classes. When creating your own errors, we encourage you to use `graphql`'s `GraphQLError` class directly; we also provide an enum of error codes that you can use to see if a given error is one of the particular types that Apollo Server provides.
+
+If you wrote this in AS3:
+
+```ts
+import { ForbiddenError } from 'apollo-server';
+throw new ForbiddenError("my message", { myExtension: "foo" })
+```
+
+you can write this in AS4:
+
+```ts
+import { GraphQLError } from 'graphql';
+throw new GraphQLError("my message", {
+ extensions: {
+ code: 'FORBIDDEN',
+ myExtension: "foo",
+ },
+});
+```
+
+For `AuthenticationError`, use code `'UNAUTHENTICATED'`.
+
+If you wrote this in AS3:
+
+```ts
+if (error instanceof SyntaxError)
+```
+
+you can write this in AS4:
+
+```ts
+import { ApolloServerErrorCode } from '@apollo/server/errors';
+if (error.extensions?.code === ApolloServerErrorCode.GRAPHQL_PARSE_FAILED)
+```
+
+For `ValidationError`, use `ApolloServerErrorCode.GRAPHQL_VALIDATION_FAILED`. For `UserInputError`, use `ApolloServerErrorCode.BAD_USER_INPUT`.
+
### `__resolveObject`
Apollo Server 4 removes the dependency on `@apollographql/apollo-tooling`, additionally removing the `__resolveObject` pseudo-resolver. The `__resolveObject` function was an undocumented predecessor to
@@ -830,40 +891,19 @@ expect(result.data?.hello).toBe('Hello world!'); // -> true
+### `formatError` hook improvements
-### Error handling changes
-
-#### ApolloError removal
-
-`ApolloError` and `toApolloError` were removed in favor of using `GraphQLError` directly.
-`GraphQLError` is exported by the `graphql` package, and you can use it in your code:
-```
-import { GraphQLError } from 'graphql';
-
-// ...
-throw new GraphQLError(message, {
- extensions: { code: 'YOUR_ERROR_CODE' },
-});
-```
-
-Note: If you previously passed the optional `code` argument as such:
-```
-throw new ApolloError(message, 'YOUR_ERROR_CODE');
-```
-You now need to pass it inside `extensions`. See above example.
-
-#### Changes to `formatError` hook
-
-Apollo Server 3 supported the `formatError` hook with the following signature:
+Apollo Server 3 supports the `formatError` hook with the following signature:
```
(error: GraphQLError) => GraphQLFormattedError
```
+The `error` received by the hook has already been transformed a bit by Apollo Server 3 from the original thrown error.
-In Apollo Server 4, it became:
+In Apollo Server 4, it becomes:
```
(formattedError: GraphQLFormattedError, error: unknown) => GraphQLFormattedError
```
-Where `formattedError` is instance `GraphQLError` serialized as plain-old object according to [GraphQL specification](https://spec.graphql.org/draft/#sec-Errors).
+Here, `formattedError` is the default JSON object that will be sent in a response according to the [GraphQL specification](https://spec.graphql.org/draft/#sec-Errors), and `error` is the exact original error that was thrown.
If you need some field from the error that isn't part of `GraphQLFormattedError`, you can access the value that was thrown initially as an `error` argument.
So now you can format errors as such:
@@ -889,7 +929,7 @@ So now you can format errors as such:
},
```
-#### Top-level error handling changes
+### HTTP error handling changes
Apollo Server 3 returns specific errors relating to GraphQL operations over HTTP/JSON as `text/plain` error messages.
From 7bf4ee95f582d6d5f0ab7ee74863f906fd2b8b46 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Wed, 20 Jul 2022 15:16:24 -0700
Subject: [PATCH 09/19] migration: gql tag
---
docs/source/migration.mdx | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index 2412bb65a79..db00b3002dd 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -615,7 +615,9 @@ In Apollo Server 4, web framework integrations such as `expressMiddleware` expec
### `gql` GraphQL tag
-TODO: explain that `gql` probably isn't even that important for servers but can be gotten directly from `graphql-tag`
+Apollo Server 3 depends on the [`graphql-tag`](https://www.npmjs.com/package/graphql-tag) npm package and re-exports its `gql` template tag function. This function is essentially a caching wrapper around `graphql-js`'s parser. Additionally, some editors know to treat the contents of `gql` strings as GraphQL. You can use this template tag if you want to define your schemas inline in your TS/JS files. (However, no Apollo Server APIs actually require you to pass in parsed documents; for example, the `typeDefs` constructor option can be a string or a parsed document.)
+
+Apollo Server 4 does not depend on or re-export the `graphql-tag` function. If you would like to continue to use `gql` in your server, simply `npm install graphql-tag` and `import gql from 'graphql-tag'` instead of `import { gql } from 'apollo-server'`. That said, you can also consider putting your schema in separate `*.graphql` files, or writing them inline as a normal string whose first line is `#graphql`; editors that recognize gql tags typically also treat these formats as GraphQL as well.
### `ApolloError`
From fd8fc38a1b7f754fb54c35e4a825549606c5a4ba Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Thu, 21 Jul 2022 09:50:04 -0700
Subject: [PATCH 10/19] Apply suggestions from code review
Co-authored-by: Rose M Koron <32436232+rkoron007@users.noreply.github.com>
---
docs/source/migration.mdx | 86 +++++++++++++++++++++------------------
1 file changed, 46 insertions(+), 40 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index db00b3002dd..7273a00887b 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -222,7 +222,10 @@ TODO: describe that plugins are now in `@apollo/server` at deep imports
### Renamed packages
-The `apollo-server-plugin-response-cache` and `apollo-server-plugin-operation-registry` plugin packages have been renamed to `@apollo/server-plugin-response-cache` and `@apollo/server-plugin-operation-registry` respectively.
+The following packages have been renamed in Apollo Server 4:
+ * `apollo-server-plugin-response-cache` is now [`@apollo/server-plugin-response-cache`](https://www.npmjs.com/package/@apollo/server-plugin-response-cache)
+ * `apollo-server-plugin-operation-registry` is now [`@apollo/server-plugin-operation-registry`](https://www.npmjs.com/package/@apollo/server-plugin-operation-registry)
+ * `apollo-reporting-protobuf` (an internal implementation detail for the usage reporting plugin) is now [`@apollo/usage-reporting-protobuf`](https://www.npmjs.com/package/@apollo/usage-reporting-protobuf)
The [`apollo-reporting-protobuf`](https://www.npmjs.com/package/apollo-reporting-protobuf) (which is an internal implementation detail of the usage reporting plugin) has been renamed to `@apollo/usage-reporting-protobuf`.
@@ -505,7 +508,7 @@ const server = new ApolloServer({
});
```
-Under the hood, Apollo Server 3's mocking functionality is provided via an outdated version of the [`@graphql-tools/mocks`](https://www.npmjs.com/package/@graphql-tools/mock) library.
+Under the hood, Apollo Server 3's mocking functionality is provided via an outdated version of the [`@graphql-tools/mocks`](https://www.npmjs.com/package/@graphql-tools/mock) library.
Apollo Server 4 removes both the `mocks` and `mockEntireSchema` constructor options. You can directly incorporate the `@graphql-tools/mock` package into your app, enabling you to get the most up-to-date mocking features. For more details on configuring mocks, see the [`@graphql-tools/mocks` docs](https://www.graphql-tools.com/docs/mocking).
@@ -532,12 +535,13 @@ console.log(`π Server listening at: ${url}`);
### `debug`
-In Apollo Server 3, the `debug` constructor option (which defaulted to true unless the `NODE_ENV` environment variable was set to `production` or `test`) controlled several unrelated aspects of Apollo Server:
-- When `debug` was set to true, stack traces are included on errors in GraphQL responses.
-- If Apollo Server was using its default `logger` implementation, messages sent at the `DEBUG` log level would be printed when `debug` was set to true. (Note that Apollo Server 3's core code wrote almost no messages at the `DEBUG` level, so this only made a difference if your plugins used the provided `logger` to send `DEBUG` messages.)
-- The `debug` flag was made available to plugins on `GraphQLRequestContext` to use as they wish.
+In Apollo Server 3, the `debug` constructor option (which defaults to `true` unless the `NODE_ENV` environment is either `production` or `test`) controls several unrelated aspects of Apollo Server:
+- When `debug` is `true`, GraphQL responses with errors include stack traces.
+- When `debug` is `true` and `ApolloServer` uses the default `logger`, all `DEBUG` log-level messages are printed.
+ - Apollo Server 3's core code rarely sends messages at the `DEBUG` level, so this primarily affects plugins that use the provided `logger` to send `DEBUG` messages.
+- The `debug` flag is available to plugins on `GraphQLRequestContext` to use as they wish.
-In Apollo Server 4, the `debug` constructor option has been removed. In its place is a new `includeStackTracesInErrorResponses` option which controls its namesake feature. Like `debug`, this option defaults to true unless the `NODE_ENV` environment variable is set to `production` or `test`. If you set `debug` in Apollo Server 3, you may want to set `includeStackTracesInErrorResponses` to the same value in Apollo Server 4.
+In Apollo Server 4, the `debug` constructor option has been removed. In its place is a new `includeStackTracesInErrorResponses` option which controls its namesake feature. Like `debug`, this option defaults to `true` unless the `NODE_ENV` environment variable is either `production` or `test`. If you use `debug` in Apollo Server 3, you can use `includeStackTracesInErrorResponses` with the same value in Apollo Server 4:
```ts
const apolloServerInstance = new ApolloServer({
@@ -547,7 +551,7 @@ const apolloServerInstance = new ApolloServer({
});
```
-Additionally, if your server did not pass a custom `logger` to `new ApolloServer` and your app or a plugin makes use of `DEBUG`-level log messages, you will need to set the default level yourself. For example, using the same `Logger` implementation that Apollo Server uses by default:
+Additionally, if your app or a plugin uses `DEBUG`-level log messages and your server doesn't use a custom `logger`, you are responsible for setting the default log level. For example, you can use the same `Logger` implementation that Apollo Server uses by default:
```ts
import loglevel from 'loglevel';
@@ -604,11 +608,11 @@ Every GraphQL server supports a trivial query that requests the [`__typename`](/
https://your.server/?query=%7B__typename%7D
```
-If you really want to have a health check in your HTTP server that is unrelated to the actual health of the GraphQL execution engine (like Apollo Server 3's health check feature), you can implement that in your web framework by just adding a GET handler that always succeeds.
+If you want a health check for your HTTP server unrelated to the health of the GraphQL execution engine (i.e., like Apollo Server 3's health check feature), you can add a GET handler that always succeeds to your web framework.
### Path parsing
-In Apollo Server 3, several web framework integrations allowed you to "mount" them at a particular URL path and then use the `path` option (which defaults to `/graphql`) to specify that they should actually only process requests at a deeper path.
+In Apollo Server 3, many framework integrations enable you to use the `path` option to configure the [URL path](/apollo-server/api/apollo-server/#path) where Apollo Server processes requests. By default, the `path` option uses the `/graphql` URL path.
In Apollo Server 4, web framework integrations such as `expressMiddleware` expect that they will be mounted at the appropriate path in the first place using the web framework's routing features. If you used an integration such as `apollo-server-express` and did not configure `path` in AS3, then to maintain the same behavior you should explicitly mount your middleware at `/graphql`. (Note that the batteries-included `apollo-server` package in AS3 (replaced by `startStandaloneServer` in AS4) served at all URLs instead of having the default of `/graphql`.)
@@ -688,9 +692,9 @@ the [`__resolveReference`](/federation/api/apollo-subgraph/#__resolvereference)
### `requestAgent` option to `ApolloServerPluginUsageReporting`
-The usage reporting plugin allows you to entirely replace its HTTP client via the `fetcher` option. Additionally, in Apollo Server 3, you could use an older `requestAgent` option, which would be passed to the `fetcher` function via the non-standard `agent` option.
+The usage reporting plugin lets you entirely replace its HTTP client via the `fetcher` option. Additionally, in Apollo Server 3, you could use an older `requestAgent` option, which is passed to the `fetcher` function via the non-standard `agent` option.
-Apollo Server 4 removes the `requestAgent` operation from `ApolloServerPluginUsageReporting`, and now only passes options that are part of the Fetch API spec to its `fetcher`. If you used `requestAgent` before, you can use the `node-fetch` npm package to override `fetcher` yourself. So if you used `requestAgent` like this:
+Apollo Server 4 removes the `requestAgent` operation from `ApolloServerPluginUsageReporting`, which means that the options passed to its `fetcher` are now all part of the Fetch API spec. If you are using `requestAgent` in Apollo Server 3, you can use the `node-fetch` npm package to override `fetcher` yourself. So, where you previously wrote:
```ts
ApolloServerPluginUsageReporting({ requestAgent })
@@ -717,7 +721,7 @@ In Apollo Server 2, the TypeScript type used for the `gateway` constructor optio
In Apollo Server 4, the legacy `GraphQLService` type is no longer exported; use `GatewayInterface` instead.
-In Apollo Server 3, the method `GatewayInterface.load` was declared to return `Promise`, which has a `schema` and an `executor`. In Apollo Server 4, `GraphQLServiceConfig` has been renamed to `GatewayLoadResult`, and it only has an `executor` field; the `onSchemaLoadOrUpdate` hook is sufficient to receive the schema.
+In Apollo Server 3, the `GatewayInterface.load` method returns `Promise`, which contains a `schema` and an `executor`. In Apollo Server 4, `GraphQLServiceConfig` has been renamed `GatewayLoadResult`, and it only has an `executor` field; you can use the `onSchemaLoadOrUpdate` hook if you want to receive the schema.
The TypeScript type `GraphQLExecutor` (the type of the `executor` field in the object returned from `GatewayInterface.load`) now returns the `ExecutionResult` type from `graphql-js` rather than the similar `GraphQLExecutionResult` type defined by Apollo Server 3. The types are essentially the same, except that `data` and `extensions` are now `Record`, rather than `Record`.
@@ -763,7 +767,7 @@ const server = new ApolloServer({
}));
```
-In Apollo Server 4, the `context` function is a named argument passed into your web integration function (such as `expressMiddleware` or `startStandaloneServer`). `ApolloServer` itself now has a generic type parameter specifying the type of your context value. The `context` function should return an object, which is then accessible to your [server's resolvers](/apollo-server/data/resolvers/#the-context-argument) and to plugins as the `contextValue` field.
+In Apollo Server 4, the `context` function is a named argument passed into your web integration function (such as `expressMiddleware` or `startStandaloneServer`). `ApolloServer` itself now has a generic type parameter specifying the type of your context value. The `context` function should return an object, which is then accessible to your [server's resolvers](/apollo-server/data/resolvers/#the-context-argument) and plugins (via the `contextValue` field).
Below is an example of providing a `context` initialization function to the `startStandaloneServer` function:
@@ -821,18 +825,18 @@ app.use(
-Note that when using `expressMiddleware`, the `req` and `res` objects passed to the `context` function are of type `express.Request` and `express.Response`, but when using `startStandaloneServer`, they are of type `http.IncomingMessage` and `http.ServerResponse`. If you need to use Express-specific properties in your context function, you should use `expressMiddleware`.
+If you are using [`expressMiddleware`](#migrating-from-apollo-server-express), the `req` and `res` objects passed to the `context` function are type `express.Request` and `express.Response`. If you are using [`startStandaloneServer`](#migrating-from-apollo-server), the `req` and `res` objects are of type `http.IncomingMessage` and `http.ServerResponse`. If you need to use Express-specific properties in your `context` function, use `expressMiddleware`.
### `executeOperation` accepts `context` object
-The [`server.executeOperation`](/apollo-server/api/apollo-server/#executeoperation) method enables you to execute GraphQL operations by specifying the operation text directly rather than by specifying them as an HTTP request. This is especially helpful for testing.
+The [`server.executeOperation`](/apollo-server/api/apollo-server/#executeoperation) method enables you to execute GraphQL operations by specifying an operation's text directly instead of doing so via an HTTP request. This is especially helpful for testing.
-In Apollo Server 3, you specify the operation's context value indirectly by passing a second optional argument which is then passed to your `ApolloServer` instance's `context` function. So for example, if you're using `apollo-server-express`, you would somehow construct an Express request and response and pass them to `executeOperation` as a `{ req, res }` object.
+In Apollo Server 3, you specify an operation's context value indirectly by passing a second optional argument to `executeOperation `, which is then passed to your `ApolloServer` instance's `context` function. For example, if you're using `apollo-server-express`, you can construct an Express request and response and then pass them to `executeOperation` as a `{ req, res }` object.
In Apollo Server 4, the `executeOperation` method instead takes a context value directly. This bypasses your `context` function. (If you'd like to test the behavior of the context function, we recommend running actual HTTP requests against your server.)
-So a test like this in Apollo Server 3:
+So a test for Apollo Server 3 that looks like this:
@@ -868,7 +872,7 @@ could be changed to something like this in Apollo Server 4:
-```ts {17-20}
+```ts {16-18}
interface MyContext {
name: string;
}
@@ -999,7 +1003,7 @@ You can no longer type `CacheScope.Public` or `CacheScope.Private`. Instead, jus
### Fields on `GraphQLRequestContext`
-Most plugin API hooks take a `GraphQLRequestContext` object as their first argument. There are several changes to this object.
+Most plugin API hooks take a `GraphQLRequestContext` object as their first argument. Apollo Server 4 makes several changes to the `GraphQLRequestContext` object.
The `context` field has been renamed to `contextValue`, for consistency with the `graphql-js` API and to differentiate from the `context` option to integration functions, which is a *function* returning a context value.
@@ -1007,7 +1011,7 @@ The `logger` and `cache` fields have been removed. These fields are now availabl
The `schemaHash` field has been removed. This field was a not particularly stable hash of a JSON encoding of the result of running the GraphQL introspection query against the schema. It was not guaranteed to change when the schema changed (eg, it is not affected by changes to schema directive applications). If you need a hash of the schema, you can hash the output of applying the `graphql-js` `printSchema` function to the `schema` field (perhaps with some sort of memoization).
-The `debug` field has been removed, because `ApolloServer` no longer has a vague `debug` option that affects multiple unrelated features. There is no direct replacement for it; if this is a problem for you, please open a GitHub issue and we can come up with an appropriate improvement (perhaps making `nodeEnv` or `includeStackTracesInErrorResponses` available as public readonly fields on `ApolloServer`).
+The `debug` field has been removed because `ApolloServer` no longer has a [vague `debug` option](#debug) that affects multiple unrelated features. There is no direct replacement for this field; if this is a problem for you, please open a GitHub issue, and we can find an appropriate improvement.
### Fields on `GraphQLServerContext`
@@ -1016,19 +1020,21 @@ The TypeScript type for the argument to the `serverWillStart` plugin hook has be
The `logger` field has been. This field is now available as a public readonly field on the `ApolloServer` object, and `GraphQLServerContext` now provides the `ApolloServer` object in a new field `server`, so `serviceContext.logger` can be replaced with `serverContext.server.logger`.
-The `schemaHash` field has been removed; see the previous section for details.
+The `schemaHash` field has been removed; see the [previous section](#fields-on-graphqlrequestcontext) for details.
-The `persistedQueries` field has been removed. We did not know of a use case for providing this particular bit of configuration to plugins (other than to a very old version of the operation cache plugin that used it). If having this available in plugins is important for you, please file a GitHub issue.
+The `persistedQueries` field has been removed. We don't have a current reason for providing this particular configuration to plugins. If having this available in plugins is important for you, please file a GitHub issue.
-The `serverlessFramework` field has been removed. The new `startedInBackground` field provides essentially the same information. (In AS3, `serverlessFramework` was true if you were using a subclass of `ApolloServer` designed for a serverless framework, which mostly affected startup error handling. In AS4, there are no subclasses; the API that implements startup error handling in a serverless-friendly way is the new `server.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()` method, and the `startedInBackground` field is true if the server was started with this method instead of with `server.start()` or something that calls `server.start()` such as `startStandaloneServer()`.)
+The `serverlessFramework` field has been removed, with the new `startedInBackground` field providing essentially the same information. In Apollo Server 3, the`serverlessFramework` field returns true if you are using a subclass of `ApolloServer` for a serverless framework (which mostly affected startup error handling). In Apollo Server 4, there are no subclasses, and the [new API](#new-approach-to-serverless-frameworks) handles startup errors in a serverless-friendly way. The `startedInBackground` field returns `true` if your server starts using the `server.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()` method.
### `GraphQLRequest`
-Apollo Server 4 refactors the `GraphQLRequest` object. (This object is available to plugins as `requestContext.request`, and is the argument to `server.executeOperation`.) Specifically, its `http` field is now a new `HTTPGraphQLRequest` type instead of a type based on the Fetch API `Request` object. This object does not contain the URL path, and its `headers` field is a `Map` (with lower-case keys) rather than a Fetch API `Headers` object.
+Apollo Server 4 refactors the `GraphQLRequest` object, which is available to plugins as `requestContext.request` and as an argument to `server.executeOperation`. Specifically, the `http` field is now a `HTTPGraphQLRequest` type instead of a type based on the Fetch API's `Request` object. The `HTTPGraphQLRequest` object does not contain a URL path, and its `headers` field is a `Map` (with lower-case keys) rather than a Fetch API `Headers` object.
### `GraphQLResponse`
-Apollo Server 4 refactors the [`GraphQLResponse` object](https://github.com/apollographql/apollo-server/blob/version-4/packages/server/src/externalTypes/graphql.ts#L25). (This object is available to plugins as `requestContext.response`, and is returned by `server.executeOperation`.) The `data`, `errors`, and `extensions` fields are now nested within an object returned by the `result` field:
+Apollo Server 4 refactors the [`GraphQLResponse` object](https://github.com/apollographql/apollo-server/blob/version-4/packages/server/src/externalTypes/graphql.ts#L25), which is available to plugins as `requestContext.response` and is returned by `server.executeOperation`.
+
+The `data`, `errors`, and `extensions` fields are now nested within an object returned by the `result` field:
```ts disableCopy
export interface GraphQLResponse {
@@ -1041,9 +1047,9 @@ export interface GraphQLResponse {
Additionally, the `data` and `extensions` fields are both type `Record`, rather than `Record`.
-`http.headers` is now a `Map` (with lower-case keys) rather than a Fetch API `Headers` object.
+The value of `http.headers` is now a `Map` (with lower-case keys) rather than a Fetch API `Headers` object.
-Note: we plan to implement experimental support for incremental delivery (`@defer`/`@stream`) before the v4.0.0 release, and we expect that this will change the structure of `GraphQLResponse` further.
+> We plan to implement experimental support for incremental delivery (`@defer`/`@stream`) before the v4.0.0 release and expect this to change the structure of `GraphQLResponse` further.
@@ -1055,7 +1061,7 @@ Errors thrown by many plugin hooks are handled more consistently by wrapping the
## Changes to defaults
-Several recommended features were introduced to Apollo Server 3 after the initial v3.0.0 release but were left off by default for backwards compatibility. In Apollo Server 4, the recommended behavior is the default. In each case, you can still configure your server to match the default behavior from Apollo Server 3 if required for compatibility.
+Apollo Server 3 introduced several recommended features after the initial v3.0.0 release, but these features were turned off by default for backward compatibility. In Apollo Server 4, the recommended behavior _is_ the default. In each case, you can still configure your server to match the default behavior of Apollo Server 3 if you want to.
### CSRF prevention is on by default
@@ -1074,11 +1080,11 @@ Not all GraphQL clients support HTTP batching, and batched requests will not sup
### Default cache is bounded
-Each Apollo Server has a cache that is used for several features, such as APQs, the response cache plugin, and `RESTDataSource`. This cache can be in-memory or use a server such as Redis, and is configured with the `cache` constructor option.
+Each Apollo Server has a cache backend used in several features, including APQs, the response cache plugin, and `RESTDataSource`. Apollo Server uses an in-memory cache by default, but you can configure it to use a different backend (such as Redis or Memcached) using the `cache` constructor option.
-In Apollo Server 3, the default cache is an unbounded in-memory cache. This is vulnerable to denial of service attacks via memory exhaustion, and we recommend that users do not use this default cache.
+In Apollo Server 3, the default cache is an _unbounded_ in-memory cache. This cache is vulnerable to denial of service attacks via memory exhaustion, and we do not recommend that users use the default cache.
-In Apollo Server 4, the default cache is a bounded in-memory cache backend (which _is safe_ for production use). This is equivalent to passing `cache: 'bounded'` in Apollo Server 3.9 or newer.
+In Apollo Server 4, the default cache is a _bounded_ in-memory cache backend (which _is safe_ for production use). This is equivalent to passing `cache: 'bounded'` in Apollo Server 3.9 or newer.
If you want to customize the cache Apollo Server uses, Apollo provides two wrapper packages to help with this process:
* [`@apollo/utils.keyvadapter`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyvAdapter) - provides a [`KeyvAdapter`](https://github.com/apollographql/apollo-utils/tree/main/packages/keyvAdapter#keyvadapter-class) wrapper class to use alongside the [`keyv`](https://www.npmjs.com/package/keyv) package.
@@ -1086,7 +1092,7 @@ If you want to customize the cache Apollo Server uses, Apollo provides two wrapp
For examples of using both `KeyvAdapter` and `InMemoryLRUCache`, see [Configuring external caching](/apollo-server/performance/cache-backends#configuring-external-caching).
-If you really want your server to use an unbounded in-memory cache like in AS3 (which may make your server vulnerable to memory exhaustion attacks), you can use the default `Keyv` implementation with no arguments:
+If you want your server to use an unbounded in-memory cache (which might make your server vulnerable to memory exhaustion attacks), you can use the default `Keyv` implementation with no arguments:
@@ -1113,7 +1119,7 @@ In Apollo Server 3, the default development landing page is a splash page contai
In Apollo Server 4, the default development landing page is the *embedded* Apollo Sandbox. Note that nothing changes about the default production landing page.
-To continue to show a splash page like in Apollo Server 3, write:
+To use the splash page from Apollo Server 3, you can add the following to your Apollo Server 4 constructor:
@@ -1183,20 +1189,20 @@ Apollo Server 4 introduces `@apollo/utils.fetcher`, which defines a minimal fetc
### Renamed types
-This section lists TypeScript-only types (such as interfaces, but not classes) whose name has been changed in Apollo Server 4 (not including those mentioned elsewhere in this guide).
+This section lists the TypeScript-only types (i.e., interfaces, not classes) whose names changed in Apollo Server 4 (not including those mentioned elsewhere in this guide).
-The name of the constructor options type has changed from `Config` to the more aptly named `ApolloServerOptions`. Some integration packages exported their own version of this type such as `ApolloServerExpressConfig`; these are no longer necessary because there is only one `ApolloServer` type with only one constructor in AS4.
+The name of the constructor options type has changed from `Config` to the more aptly named `ApolloServerOptions`. In Apollo Server 3, some integration packages export their own versions of this type (e.g., `ApolloServerExpressConfig`). In Apollo Server 4, there is only one `ApolloServer` type with only one constructor, so these additional types are no longer necessary.
-Two types in `apollo-server-express` now have more explicit names exported from `@apollo/server/express4`. `GetMiddlewareOptions` is now `ExpressMiddlewareOptions`, and `ExpressContext` is now `ExpressContextFunctionArgument`.
+Two types in `apollo-server-express` now have more explicit names exported from `@apollo/server/express4`. `GetMiddlewareOptions` is now `ExpressMiddlewareOptions` and `ExpressContext` is now `ExpressContextFunctionArgument`.
### Removed types
-This section lists TypeScript-only types (such as interfaces, but not classes) which have been removed in Apollo Server 4 (not including those mentioned elsewhere in this guide).
+This section lists the TypeScript-only types (i.e., interfaces, not classes) whose names are removed in Apollo Server 4 (not including those mentioned elsewhere in this guide).
-`GraphQLOptions` was an internal type used to create integrations which was only exported for technical reasons. It no longer exists.
+`GraphQLOptions` was an internal type used to create integrations and was exported for technical reasons; it is now gone.
`ServerRegistration` was related to `applyMiddleware`, which no longer exists.
`CorsOptions` and `OptionsJson` were re-exported from the `cors` and `body-parser` packages. Because Apollo Server 4 no longer handles these tasks for you, these types are no longer re-exported.
-`ServerInfo` (returned from `server.listen()` in `apollo-server`) no longer exists. `startStandaloneServer` returns a simpler data structure that currently has no type name.
+`ServerInfo` (returned from `server.listen()` in `apollo-server`) no longer exists. The `startStandaloneServer` function returns a simpler data structure with no type name.
From 22e7d12432fd2c74976c228833b256c8088c2a27 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Thu, 21 Jul 2022 15:21:11 -0700
Subject: [PATCH 11/19] Apply suggestions from code review
Co-authored-by: Rose M Koron <32436232+rkoron007@users.noreply.github.com>
---
docs/source/migration.mdx | 71 ++++++++++++++++++++++-----------------
1 file changed, 41 insertions(+), 30 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index 7273a00887b..ff48e13b008 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -22,7 +22,9 @@ During Apollo Server 4's alpha, we are actively looking to gather feedback and [
TODO: Maybe rename section?
-Apollo Server 3 ships with a fixed set of integrations with a variety of web frameworks and serverless environments, but does not provided a supported mechanism for integrating with additional frameworks. In Apollo Server 3, changes to framework integrations could only be released with lockstep versioning with Apollo Server itself, which has made it challenging to support multiple major versions of frameworks or make other integration-specific changes. Each of these integrations are released in a separate package, such as `apollo-server-express` or `apollo-server-lambda`. The core logic is implemented in a variety of packages, most notably `apollo-server-core`. This package defines an `ApolloServer` "base" class, and each integration package exports a subclass with the same name with slightly different APIs. Additionally, the `apollo-server` package is a "batteries-included" package which wraps `apollo-server-express` and provides a full HTTP server without the need to learn about a particular web framework, while providing minimal opportunities for HTTP-level customization.
+Apollo Server 3 is distributed as a [fixed set of packages](/apollo-server/integrations/middleware) for integrating with different web frameworks and environments. The main "batteries-included" [`apollo-server` package](/apollo-server/integrations/middleware#apollo-server) reduces setup time by providing a minimally customizable GraphQL server. Apollo Server 3 doesn't provide a way to add new integrations for additional frameworks.
+
+In Apollo Server 3, the `apollo-server-core` package defines an `ApolloServer` "base" class, which each integration package (e.g., `apollo-server-express`,`apollo-server-lambda`, etc. ) exports as a subclass with the same name and a slightly different API. This packaging structure means that new integration package releases are lockstep versioned to Apollo Server itself, making it challenging to support major versions of frameworks and add integration-specific changes.
Apollo Server 4 takes a different approach to integrations. Apollo Server 4 has a stable web framework integration API, which includes explicit support for serverless framework life cycles. The new `@apollo/server` package contains the `ApolloServer` class, an [Express 4 integration](#migrating-from-apollo-server-express) (similar to AS3's `apollo-server-express` package), and a [standalone server](#migrating-from-apollo-server) (similar to AS3's `apollo-server` package). There are no subclasses in AS4; there is a single `ApolloServer` class with a single API that all integrations use.
@@ -111,11 +113,11 @@ If you used the `apollo-server-express` package in Apollo Server 3, you'll use t
To migrate from AS3's `apollo-server-express` package to using the `expressMiddleware` function, you'll need to do the following:
- Install the `@apollo/server`, `cors`, and `body-parser` packages.
-- Import symbols from `@apollo/server` (instead of `apollo-server-express` and `apollo-server-core`).
+- Import symbols from `@apollo/server` (i.e., instead of from `apollo-server-express` and `apollo-server-core`).
- Add `cors` and `bodyParser.json()` to your server setup.
- Remove the Apollo Server 3 `apollo-server-express` and `apollo-server-core` packages.
-Note that by default, `apollo-server-express` in AS3 would only actually respond to operations on `/graphql`, so we explicitly mount `expressMiddleware` at that path in AS4.
+If using `apollo-server-express`'s default `/graphql` URL path (i.e., not specifying another URL with the [path option](/apollo-server/api/apollo-server/#path)), you can mount `expressMiddleware` at `/graphql` to maintain the same behavior. To use another URL path, mount your server (with `app.use`) at the specified path.
@@ -484,7 +486,7 @@ console.log(`Server ready at ${url}`);
### `modules`
-In Apollo Server 3, there are [several ways](https://github.com/apollographql/apollo-server/issues/6062) to provide your `ApolloServer` instance with a schema. One of these ways is to provide `typeDefs` and `resolvers` options (each of which can optionally be an array). Another way is to use the `modules` option with an array of objects, each of which have `typeDefs` and `resolvers` keys. Surprisingly, these two options used entirely different implementations of "create a schema from `typeDefs` and `resolvers`" under the hood.
+In Apollo Server 3, there are [several ways](https://github.com/apollographql/apollo-server/issues/6062) to provide your `ApolloServer` instance with a schema. One of the most common ways is to provide `typeDefs` and `resolvers` options (each of which can optionally be an array). Another way is using the `modules` option with an array of objects, each object containing `typeDefs` and `resolvers` keys. Under the hood, these two options use entirely different logic to do the same thing.
To simplify its API, Apollo Server 4 removes the `modules` constructor option. You can replace any previous usage of `modules` with the following syntax:
@@ -614,21 +616,30 @@ If you want a health check for your HTTP server unrelated to the health of the G
In Apollo Server 3, many framework integrations enable you to use the `path` option to configure the [URL path](/apollo-server/api/apollo-server/#path) where Apollo Server processes requests. By default, the `path` option uses the `/graphql` URL path.
-In Apollo Server 4, web framework integrations such as `expressMiddleware` expect that they will be mounted at the appropriate path in the first place using the web framework's routing features. If you used an integration such as `apollo-server-express` and did not configure `path` in AS3, then to maintain the same behavior you should explicitly mount your middleware at `/graphql`. (Note that the batteries-included `apollo-server` package in AS3 (replaced by `startStandaloneServer` in AS4) served at all URLs instead of having the default of `/graphql`.)
+In Apollo Server 4, you should use your framework's routing feature to mount your integration at the URL path where you want Apollo Server to process requests. For example, if you are using `apollo-server-express` in AS3 and would like to continue using the default `/graphql` path, you should now mount the `expressMiddleware` function at the `/graphql` path.
+
+> Apollo Server 3's batteries-included `apollo-server` package, replaced by `startStandAloneServer` in Apollo Server 4, serves all URLs (i.e., rather than only listening on `/graphql`).
### `gql` GraphQL tag
-Apollo Server 3 depends on the [`graphql-tag`](https://www.npmjs.com/package/graphql-tag) npm package and re-exports its `gql` template tag function. This function is essentially a caching wrapper around `graphql-js`'s parser. Additionally, some editors know to treat the contents of `gql` strings as GraphQL. You can use this template tag if you want to define your schemas inline in your TS/JS files. (However, no Apollo Server APIs actually require you to pass in parsed documents; for example, the `typeDefs` constructor option can be a string or a parsed document.)
+Apollo Server 3 depends on the [`graphql-tag`](https://www.npmjs.com/package/graphql-tag) npm package and re-exports its `gql` template literal tag. The `gql` tag is essentially a caching wrapper around `graphql-js`'s parser, and most IDEs know to treat the contents of `gql` strings as GraphQL. In Apollo Server 3, you can use a string or a `gql` template string to define an inline schema before passing it to the `typeDefs` constructor option.
+
+Apollo Server 4 does not depend on the `graphql-tag` library, nor does it export the `gql` tag. If you want to continue using the `gql` tag, you can directly install `graphql-tag` into your app, then update your import:
-Apollo Server 4 does not depend on or re-export the `graphql-tag` function. If you would like to continue to use `gql` in your server, simply `npm install graphql-tag` and `import gql from 'graphql-tag'` instead of `import { gql } from 'apollo-server'`. That said, you can also consider putting your schema in separate `*.graphql` files, or writing them inline as a normal string whose first line is `#graphql`; editors that recognize gql tags typically also treat these formats as GraphQL as well.
+``ts
+// import { gql } from 'apollo-server' (Removing this line)
+import gql from 'graphql-tag' (Adding this line)
+``
+
+You can alternatively separate your schema into `*.graphql` files or write your schema as a string whose first line is `#graphql` (editors that recognize `gql` tags also treat this string format as GraphQL).
### `ApolloError`
-`ApolloError` and `toApolloError` were removed in favor of using `GraphQLError` directly.
-`GraphQLError` is exported by the `graphql` package, and you can use it in your code:
-```
+Apollo Server 4 removes both `ApolloError` and `toApolloError` in favor of directly using `GraphQLError`.
+The `graphql` package exports `GraphQLError`, and you can use it like so:
+```ts
import { GraphQLError } from 'graphql';
// ...
@@ -637,26 +648,26 @@ throw new GraphQLError(message, {
});
```
-Note: If you previously passed the optional `code` argument as such:
+If you use the optional `code` argument with `ApolloError`, like so:
```
throw new ApolloError(message, 'YOUR_ERROR_CODE');
```
-You now need to pass it inside `extensions`. See above example.
+You should now pass your error code to the `extensions` option; see the above code snippet for an example.
### Built-in error classes
-Apollo Server 3 exports a number of specific error classes. Some of them (`SyntaxError`, `ValidationError`, and `UserInputError`) are produced by Apollo Server's own code. Others (`ForbiddenError` and `AuthenticationError`) are provided for users to use in their apps. These are subclasses of the `ApolloError` class.
+Apollo Server 3 exports several specific error classes. Apollo Server's code produces some of them (`SyntaxError`, `ValidationError`, and `UserInputError`). Others (`ForbiddenError` and `AuthenticationError`) are provided for users to use in their apps. All of these are subclasses of the `ApolloError` class.
-In Apollo Server 4 (as described above) `ApolloError` no longer exists, and we no longer export the specific error classes. When creating your own errors, we encourage you to use `graphql`'s `GraphQLError` class directly; we also provide an enum of error codes that you can use to see if a given error is one of the particular types that Apollo Server provides.
+In Apollo Server 4, [`ApolloError` no longer exists](#apolloerror), so Apollo Server doesn't export specific error classes. You can create your own error codes using `graphql`'s `GraphQLError` class. Additionally, Apollo Server now provides an enum of error codes ([`ApolloServerErrorCode`](https://github.com/apollographql/apollo-server/blob/version-4/packages/server/src/errors/index.ts)) that you can check against to see if a given error is one of the error types recognized by Apollo Server.
-If you wrote this in AS3:
+In Apollo Server 3, you can throw a new `ForbiddenError`, like so:
```ts
import { ForbiddenError } from 'apollo-server';
throw new ForbiddenError("my message", { myExtension: "foo" })
```
-you can write this in AS4:
+In Apollo Server 4, you should define your own error using `GraphQLError`, like so:
```ts
import { GraphQLError } from 'graphql';
@@ -668,15 +679,15 @@ throw new GraphQLError("my message", {
});
```
-For `AuthenticationError`, use code `'UNAUTHENTICATED'`.
+For an `AuthenticationError`, use the code `'UNAUTHENTICATED'`.
-If you wrote this in AS3:
+In Apollo Server 3, you can check the type of an error, like so:
```ts
if (error instanceof SyntaxError)
```
-you can write this in AS4:
+In Apollo Server 4, you can use the `ApolloServerErrorCode` enum to check if an error is one of the types recognized by Apollo Server, like so:
```ts
import { ApolloServerErrorCode } from '@apollo/server/errors';
@@ -834,7 +845,7 @@ The [`server.executeOperation`](/apollo-server/api/apollo-server/#executeoperati
In Apollo Server 3, you specify an operation's context value indirectly by passing a second optional argument to `executeOperation `, which is then passed to your `ApolloServer` instance's `context` function. For example, if you're using `apollo-server-express`, you can construct an Express request and response and then pass them to `executeOperation` as a `{ req, res }` object.
-In Apollo Server 4, the `executeOperation` method instead takes a context value directly. This bypasses your `context` function. (If you'd like to test the behavior of the context function, we recommend running actual HTTP requests against your server.)
+In Apollo Server 4, the `executeOperation` method optionally receives a context value directly, bypassing your `context` function. If you want to test the behavior of your `context` function, we recommend running actual HTTP requests against your server.
So a test for Apollo Server 3 that looks like this:
@@ -868,7 +879,7 @@ expect(result.data?.hello).toBe('Hello world!'); // -> true
-could be changed to something like this in Apollo Server 4:
+can be rewritten in Apollo Server 4, like so:
@@ -995,7 +1006,7 @@ In Apollo Server 4, `CacheScope` is now a union of strings (`PUBLIC` or `PRIVAT
export type CacheScope = 'PUBLIC' | 'PRIVATE';
```
-You can no longer type `CacheScope.Public` or `CacheScope.Private`. Instead, just use the string `'PUBLIC'` or `'PRIVATE'`. Values defined as `CacheScope` will only accept those two values, so typos will still be caught at compile time.
+You can no longer type `CacheScope.Public` or `CacheScope.Private`. Instead, just use the string `'PUBLIC'` or `'PRIVATE'`. Values defined as `CacheScope` will only accept those two values, so any typos are still caught at compile time.
@@ -1005,11 +1016,11 @@ You can no longer type `CacheScope.Public` or `CacheScope.Private`. Instead, jus
Most plugin API hooks take a `GraphQLRequestContext` object as their first argument. Apollo Server 4 makes several changes to the `GraphQLRequestContext` object.
-The `context` field has been renamed to `contextValue`, for consistency with the `graphql-js` API and to differentiate from the `context` option to integration functions, which is a *function* returning a context value.
+The `context` field has been renamed `contextValue`, for consistency with the `graphql-js` API and to help differentiate from the `context` option of integration functions (the *function* which returns a context value).
-The `logger` and `cache` fields have been removed. These fields are now available as public readonly fields on the `ApolloServer` object, and `GraphQLRequestContext` now provides the `ApolloServer` object in a new field `server`, so `requestContext.logger` and `requestContext.cache` can be replaced with `requestContext.server.logger` and `requestContext.server.cache` respectively.
+The `logger` and `cache` fields have been removed from `GraphQLRequestContext`, and are only available as `public readonly` fields on the `ApolloServer` object. `GraphQLRequestContext` now provides the `ApolloServer` object in a new field named `server`. This means `requestContext.logger` and `requestContext.cache` can be replaced with `requestContext.server.logger` and `requestContext.server.cache` respectively.
-The `schemaHash` field has been removed. This field was a not particularly stable hash of a JSON encoding of the result of running the GraphQL introspection query against the schema. It was not guaranteed to change when the schema changed (eg, it is not affected by changes to schema directive applications). If you need a hash of the schema, you can hash the output of applying the `graphql-js` `printSchema` function to the `schema` field (perhaps with some sort of memoization).
+The `schemaHash` field has been removed. This field is an unstable hash of a JSON encoding of the result of running the GraphQL introspection query against the schema. The `schemaHash` field is not guaranteed to change when the schema changes (e.g., it is not affected by changes to schema directive applications). If you want a schema hash, you can hash the output of applying `graphql-js`'s `printSchema` function to the `schema` field (perhaps using some sort of memorization).
The `debug` field has been removed because `ApolloServer` no longer has a [vague `debug` option](#debug) that affects multiple unrelated features. There is no direct replacement for this field; if this is a problem for you, please open a GitHub issue, and we can find an appropriate improvement.
@@ -1018,7 +1029,7 @@ The `debug` field has been removed because `ApolloServer` no longer has a [vague
The TypeScript type for the argument to the `serverWillStart` plugin hook has been renamed from `GraphQLServiceContext` to `GraphQLServerContext`, for consistency with the hook name.
-The `logger` field has been. This field is now available as a public readonly field on the `ApolloServer` object, and `GraphQLServerContext` now provides the `ApolloServer` object in a new field `server`, so `serviceContext.logger` can be replaced with `serverContext.server.logger`.
+The `logger` field has been removed. This field is now available as a `public readonly` field on the `ApolloServer` object, which `GraphQLServerContext` provides via a new field named `server`. This means `serviceContext.logger` can be replaced with `serverContext.server.logger`.
The `schemaHash` field has been removed; see the [previous section](#fields-on-graphqlrequestcontext) for details.
@@ -1055,9 +1066,9 @@ The value of `http.headers` is now a `Map` (with lower-case keys) rather than a
### Changes to plugin semantics
-`requestDidStart` hooks are called in parallel rather than in series.
+In Apollo Server 4, `requestDidStart` hooks are called in parallel rather than in series.
-Errors thrown by many plugin hooks are handled more consistently by wrapping the error in an "Unexpected error handling request" error and invoking the new `unexpectedErrorProcessingRequest` plugin hook.
+Apollo Server 4 more consistently handles errors thrown by multiple plugin hooks. Each error is wrapped in an "Unexpected error handling request" error and invoked using the new `unexpectedErrorProcessingRequest` plugin hook.
## Changes to defaults
@@ -1115,7 +1126,7 @@ new ApolloServer({
### Local landing page defaults to Embedded Apollo Sandbox
-In Apollo Server 3, the default development landing page is a splash page containing a link to Apollo Sandbox hosted at https://studio.apollographql.com/. This hosted Sandbox only works if your server's CORS configuration allows the origin https://studio.apollographql.com/ to talk to it. You can also configure `ApolloServerPluginLandingPageLocalDefault` with `embed: true` to embed Apollo Sandbox directly in the landing page; in this mode, Sandbox is able to make same-origin requests to your server and no CORS configuration is necessary.
+In Apollo Server 3, the default development landing page is a splash page containing a link to the Apollo Sandbox (hosted at `https://studio.apollographql.com/`). This Sandbox only works if your server's CORS configuration allows the origin `https://studio.apollographql.com/ `. The [`ApolloServerPluginLandingPageLocalDefault`](apollo-server/testing/build-run-queries/#configuring-the-default-landing-page) plugin enables you to embed Apollo Sandbox directly on your server's landing page. Passing `embed: true` to the `ApolloServerPluginLandingPageLocalDefault` plugin allows your sandbox to make same-origin requests to your server with no additional CORS configuration.
In Apollo Server 4, the default development landing page is the *embedded* Apollo Sandbox. Note that nothing changes about the default production landing page.
@@ -1142,7 +1153,7 @@ new ApolloServer({
## TypeScript-only changes
-Some changes only affect TypeScript typings, not runtime behavior. For example, we have changed some of the names of TypeScript interfaces to be more clear, and we've changed what packages we use to define other interfaces. (Changes that affect more than just typings (like renaming `GraphQLServiceContext` and `GraphQLServiceConfig`) are described elsewhere.)
+Several Apollo Server 4 changes only affect TypeScript typings, not runtime behavior. For example, we renamed specific TypeScript interfaces to be more straightforward and changed which packages we used to define other interfaces. Changes that affect more than just typings (e.g., renaming `GraphQLServiceContext` and `GraphQLServiceConfig`) are described elsewhere.
### Improved typing for `context`
From db061208912c3b8ddc0ecfba38c2e41ffdc43380 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Thu, 21 Jul 2022 15:25:41 -0700
Subject: [PATCH 12/19] Tweak gql section
including re-adding triple-quotes because GH suggestions don't like
them. And I guess trimming trailing newlines which I guess my editor
does and which got introduced recently?
---
docs/source/migration.mdx | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index ff48e13b008..644c47f542f 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -24,7 +24,7 @@ TODO: Maybe rename section?
Apollo Server 3 is distributed as a [fixed set of packages](/apollo-server/integrations/middleware) for integrating with different web frameworks and environments. The main "batteries-included" [`apollo-server` package](/apollo-server/integrations/middleware#apollo-server) reduces setup time by providing a minimally customizable GraphQL server. Apollo Server 3 doesn't provide a way to add new integrations for additional frameworks.
-In Apollo Server 3, the `apollo-server-core` package defines an `ApolloServer` "base" class, which each integration package (e.g., `apollo-server-express`,`apollo-server-lambda`, etc. ) exports as a subclass with the same name and a slightly different API. This packaging structure means that new integration package releases are lockstep versioned to Apollo Server itself, making it challenging to support major versions of frameworks and add integration-specific changes.
+In Apollo Server 3, the `apollo-server-core` package defines an `ApolloServer` "base" class, which each integration package (e.g., `apollo-server-express`,`apollo-server-lambda`, etc. ) exports as a subclass with the same name and a slightly different API. This packaging structure means that new integration package releases are lockstep versioned to Apollo Server itself, making it challenging to support major versions of frameworks and add integration-specific changes.
Apollo Server 4 takes a different approach to integrations. Apollo Server 4 has a stable web framework integration API, which includes explicit support for serverless framework life cycles. The new `@apollo/server` package contains the `ApolloServer` class, an [Express 4 integration](#migrating-from-apollo-server-express) (similar to AS3's `apollo-server-express` package), and a [standalone server](#migrating-from-apollo-server) (similar to AS3's `apollo-server` package). There are no subclasses in AS4; there is a single `ApolloServer` class with a single API that all integrations use.
@@ -539,7 +539,7 @@ console.log(`π Server listening at: ${url}`);
In Apollo Server 3, the `debug` constructor option (which defaults to `true` unless the `NODE_ENV` environment is either `production` or `test`) controls several unrelated aspects of Apollo Server:
- When `debug` is `true`, GraphQL responses with errors include stack traces.
-- When `debug` is `true` and `ApolloServer` uses the default `logger`, all `DEBUG` log-level messages are printed.
+- When `debug` is `true` and `ApolloServer` uses the default `logger`, all `DEBUG` log-level messages are printed.
- Apollo Server 3's core code rarely sends messages at the `DEBUG` level, so this primarily affects plugins that use the provided `logger` to send `DEBUG` messages.
- The `debug` flag is available to plugins on `GraphQLRequestContext` to use as they wish.
@@ -616,23 +616,23 @@ If you want a health check for your HTTP server unrelated to the health of the G
In Apollo Server 3, many framework integrations enable you to use the `path` option to configure the [URL path](/apollo-server/api/apollo-server/#path) where Apollo Server processes requests. By default, the `path` option uses the `/graphql` URL path.
-In Apollo Server 4, you should use your framework's routing feature to mount your integration at the URL path where you want Apollo Server to process requests. For example, if you are using `apollo-server-express` in AS3 and would like to continue using the default `/graphql` path, you should now mount the `expressMiddleware` function at the `/graphql` path.
+In Apollo Server 4, you should use your framework's routing feature to mount your integration at the URL path where you want Apollo Server to process requests. For example, if you are using `apollo-server-express` in AS3 and would like to continue using the default `/graphql` path, you should now mount the `expressMiddleware` function at the `/graphql` path.
> Apollo Server 3's batteries-included `apollo-server` package, replaced by `startStandAloneServer` in Apollo Server 4, serves all URLs (i.e., rather than only listening on `/graphql`).
### `gql` GraphQL tag
-Apollo Server 3 depends on the [`graphql-tag`](https://www.npmjs.com/package/graphql-tag) npm package and re-exports its `gql` template literal tag. The `gql` tag is essentially a caching wrapper around `graphql-js`'s parser, and most IDEs know to treat the contents of `gql` strings as GraphQL. In Apollo Server 3, you can use a string or a `gql` template string to define an inline schema before passing it to the `typeDefs` constructor option.
+Apollo Server 3 depends on the [`graphql-tag`](https://www.npmjs.com/package/graphql-tag) npm package and re-exports its `gql` template literal tag. The `gql` tag is essentially a caching wrapper around `graphql-js`'s parser, and most IDEs know to treat the contents of `gql` strings as GraphQL.
Apollo Server 4 does not depend on the `graphql-tag` library, nor does it export the `gql` tag. If you want to continue using the `gql` tag, you can directly install `graphql-tag` into your app, then update your import:
-``ts
+```ts
// import { gql } from 'apollo-server' (Removing this line)
import gql from 'graphql-tag' (Adding this line)
-``
+```
-You can alternatively separate your schema into `*.graphql` files or write your schema as a string whose first line is `#graphql` (editors that recognize `gql` tags also treat this string format as GraphQL).
+However, no Apollo Server APIs (in v3 or v4) actually require you to pass in the parsed document produced by a `gql` template string; for example, the `typeDefs` constructor option allows your schema to be specified either as a string or as a parsed document. Rather than switching to the `graphql-tag` package, you may wish to simply specify your schema as a string (whether inline in your source file, or in a separate `*.graphql` file that you read in your code). Note that most editors that recognize `gql` tags also treat any string starting with `#graphql` as GraphQL.
### `ApolloError`
@@ -660,7 +660,7 @@ Apollo Server 3 exports several specific error classes. Apollo Server's code pro
In Apollo Server 4, [`ApolloError` no longer exists](#apolloerror), so Apollo Server doesn't export specific error classes. You can create your own error codes using `graphql`'s `GraphQLError` class. Additionally, Apollo Server now provides an enum of error codes ([`ApolloServerErrorCode`](https://github.com/apollographql/apollo-server/blob/version-4/packages/server/src/errors/index.ts)) that you can check against to see if a given error is one of the error types recognized by Apollo Server.
-In Apollo Server 3, you can throw a new `ForbiddenError`, like so:
+In Apollo Server 3, you can throw a new `ForbiddenError`, like so:
```ts
import { ForbiddenError } from 'apollo-server';
@@ -1014,7 +1014,7 @@ You can no longer type `CacheScope.Public` or `CacheScope.Private`. Instead, jus
### Fields on `GraphQLRequestContext`
-Most plugin API hooks take a `GraphQLRequestContext` object as their first argument. Apollo Server 4 makes several changes to the `GraphQLRequestContext` object.
+Most plugin API hooks take a `GraphQLRequestContext` object as their first argument. Apollo Server 4 makes several changes to the `GraphQLRequestContext` object.
The `context` field has been renamed `contextValue`, for consistency with the `graphql-js` API and to help differentiate from the `context` option of integration functions (the *function* which returns a context value).
@@ -1035,7 +1035,7 @@ The `schemaHash` field has been removed; see the [previous section](#fields-on-g
The `persistedQueries` field has been removed. We don't have a current reason for providing this particular configuration to plugins. If having this available in plugins is important for you, please file a GitHub issue.
-The `serverlessFramework` field has been removed, with the new `startedInBackground` field providing essentially the same information. In Apollo Server 3, the`serverlessFramework` field returns true if you are using a subclass of `ApolloServer` for a serverless framework (which mostly affected startup error handling). In Apollo Server 4, there are no subclasses, and the [new API](#new-approach-to-serverless-frameworks) handles startup errors in a serverless-friendly way. The `startedInBackground` field returns `true` if your server starts using the `server.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()` method.
+The `serverlessFramework` field has been removed, with the new `startedInBackground` field providing essentially the same information. In Apollo Server 3, the`serverlessFramework` field returns true if you are using a subclass of `ApolloServer` for a serverless framework (which mostly affected startup error handling). In Apollo Server 4, there are no subclasses, and the [new API](#new-approach-to-serverless-frameworks) handles startup errors in a serverless-friendly way. The `startedInBackground` field returns `true` if your server starts using the `server.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests()` method.
### `GraphQLRequest`
@@ -1043,7 +1043,7 @@ Apollo Server 4 refactors the `GraphQLRequest` object, which is available to plu
### `GraphQLResponse`
-Apollo Server 4 refactors the [`GraphQLResponse` object](https://github.com/apollographql/apollo-server/blob/version-4/packages/server/src/externalTypes/graphql.ts#L25), which is available to plugins as `requestContext.response` and is returned by `server.executeOperation`.
+Apollo Server 4 refactors the [`GraphQLResponse` object](https://github.com/apollographql/apollo-server/blob/version-4/packages/server/src/externalTypes/graphql.ts#L25), which is available to plugins as `requestContext.response` and is returned by `server.executeOperation`.
The `data`, `errors`, and `extensions` fields are now nested within an object returned by the `result` field:
@@ -1072,7 +1072,7 @@ Apollo Server 4 more consistently handles errors thrown by multiple plugin hooks
## Changes to defaults
-Apollo Server 3 introduced several recommended features after the initial v3.0.0 release, but these features were turned off by default for backward compatibility. In Apollo Server 4, the recommended behavior _is_ the default. In each case, you can still configure your server to match the default behavior of Apollo Server 3 if you want to.
+Apollo Server 3 introduced several recommended features after the initial v3.0.0 release, but these features were turned off by default for backward compatibility. In Apollo Server 4, the recommended behavior _is_ the default. In each case, you can still configure your server to match the default behavior of Apollo Server 3 if you want to.
### CSRF prevention is on by default
@@ -1202,7 +1202,7 @@ Apollo Server 4 introduces `@apollo/utils.fetcher`, which defines a minimal fetc
This section lists the TypeScript-only types (i.e., interfaces, not classes) whose names changed in Apollo Server 4 (not including those mentioned elsewhere in this guide).
-The name of the constructor options type has changed from `Config` to the more aptly named `ApolloServerOptions`. In Apollo Server 3, some integration packages export their own versions of this type (e.g., `ApolloServerExpressConfig`). In Apollo Server 4, there is only one `ApolloServer` type with only one constructor, so these additional types are no longer necessary.
+The name of the constructor options type has changed from `Config` to the more aptly named `ApolloServerOptions`. In Apollo Server 3, some integration packages export their own versions of this type (e.g., `ApolloServerExpressConfig`). In Apollo Server 4, there is only one `ApolloServer` type with only one constructor, so these additional types are no longer necessary.
Two types in `apollo-server-express` now have more explicit names exported from `@apollo/server/express4`. `GetMiddlewareOptions` is now `ExpressMiddlewareOptions` and `ExpressContext` is now `ExpressContextFunctionArgument`.
@@ -1210,7 +1210,7 @@ Two types in `apollo-server-express` now have more explicit names exported from
This section lists the TypeScript-only types (i.e., interfaces, not classes) whose names are removed in Apollo Server 4 (not including those mentioned elsewhere in this guide).
-`GraphQLOptions` was an internal type used to create integrations and was exported for technical reasons; it is now gone.
+`GraphQLOptions` was an internal type used to create integrations and was exported for technical reasons; it is now gone.
`ServerRegistration` was related to `applyMiddleware`, which no longer exists.
From 90dc9305ab19e9d029f530450acb24ecb1f7ee98 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Thu, 21 Jul 2022 16:17:52 -0700
Subject: [PATCH 13/19] Simplify some bullets and add body-parser/cors section
back
---
docs/source/migration.mdx | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index 644c47f542f..6f77c6a82ef 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -48,11 +48,11 @@ If you are using any other Apollo Server 3 framework integration package, you ca
There are a few other high-level changes to how you work with framework integrations. There are more details on each of these changes in later sections.
-- In Apollo Server 3, you pass your `context` function to the `ApolloServer` constructor. The parameters received by this function depend on which `ApolloServer` subclass you are using. Because Apollo Server 4 does not use subclassing, you no longer pass your `context` function to the `ApolloServer` constructor; instead, you pass it to your integration function (eg, `expressMiddleware` or `startStandaloneServer`).
-- In Apollo Server 3, the framework integrations automatically set up their framework's HTTP body parsing and CORS header writing for you, and you could configure that functionality in a framework-specific way via the Apollo Server API. In Apollo Server 4, it's your responsibility to set up these standard features yourself. Specifically, when using `expressMiddleware`, you should install the `body-parser` and `cors` npm packages and use them in your Express app, just like with any other JSON-based API server. Note that `startStandaloneServer` does set up these packages for you automatically, but does not allow you to configure their behavior.
-- In Apollo Server 3, some framework integrations take a `path` option that lets you configure on what URL path they listen on, with a default of `/graphql`. This feature overlapped with the router features defined by web frameworks and has been removed in Apollo Server 4. This means that to provide the same API when migrating, you'll want to explicitly mount `expressMiddleware` at `/graphql`. (Note that the AS3 batteries-included server `apollo-server` listened on all paths, not just `/graphql`.)
+- Your [`context` function](#context-initialization-function) is passed to your integration function (eg, `expressMiddleware` or `startStandaloneServer`) instead of the `ApolloServer` constructor.
+- When using a framework integration, you now need to [set up HTTP body parsing and CORS yourself](#body-parser-and-cors) using your framework's standard functionality.
+- Instead of [telling the framework integration function what URL path to listen](#path-parsing) on with a `path` option, pass that path directly to your framework's router. If you did not specify a path, the default in Apollo Server 3 was `/graphql`, so to preserve existing behavior you should explicitly specify that path now.
-The follow sections show how servers using `apollo-server` and `apollo-server-express` need to change to use the new API.
+The following sections shows how servers using `apollo-server` and `apollo-server-express` need to change to use the new API.
### Migrating from `apollo-server`
@@ -621,6 +621,15 @@ In Apollo Server 4, you should use your framework's routing feature to mount you
> Apollo Server 3's batteries-included `apollo-server` package, replaced by `startStandAloneServer` in Apollo Server 4, serves all URLs (i.e., rather than only listening on `/graphql`).
+### `body-parser` and `cors`
+
+In Apollo Server 3, framework integrations automatically set up their framework's HTTP body parsing and CORS response header functionality for you, and you could configure that functionality in a framework-specific way via the Apollo Server API. The details of this configuration varied by integration, but typically involved options passed to either the `ApolloServer` constructor or a method such as `applyMiddleware`, with names such as `bodyParserConfig` and `cors`.
+
+In Apollo Server 4, it's your responsibility to set up these standard features yourself when using a web framework. Specifically, when using `expressMiddleware`, you should install the `body-parser` and `cors` npm packages and use them in your Express app, just like with any other JSON-based API server. If you passed a `cors` option to `applyMiddleware` or `getMiddleware`, you should pass the same value to the `cors` function. If you passed a `bodyParserConfig` option to `applyMiddleware` or `getMiddleware`, you should pass the same value to the `body-parser` package's `json` function.
+
+Note that `startStandaloneServer` does set up body parsing and CORS functionality for you, but does not allow you to configure their behavior. In Apollo Server 3, you could configure the batteries-included `apollo-server`'s CORS behavior via the `cors` constructor option (although you could not configure body parsing). In Apollo Server 4, if you need to configure CORS behavior, use `expressMiddleware` rather than `startStandaloneServer`.
+
+
### `gql` GraphQL tag
Apollo Server 3 depends on the [`graphql-tag`](https://www.npmjs.com/package/graphql-tag) npm package and re-exports its `gql` template literal tag. The `gql` tag is essentially a caching wrapper around `graphql-js`'s parser, and most IDEs know to treat the contents of `gql` strings as GraphQL.
From 36307f9b6cd6e94a53acef4106a61a4f01b9876f Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Thu, 21 Jul 2022 16:24:10 -0700
Subject: [PATCH 14/19] A few @trevor-scheer related changes
---
docs/source/migration.mdx | 4 ++--
packages/plugin-response-cache/package.json | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index 6f77c6a82ef..a505e074ee4 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -231,7 +231,7 @@ The following packages have been renamed in Apollo Server 4:
The [`apollo-reporting-protobuf`](https://www.npmjs.com/package/apollo-reporting-protobuf) (which is an internal implementation detail of the usage reporting plugin) has been renamed to `@apollo/usage-reporting-protobuf`.
-Note that once AS4 is released, all actively maintained Apollo packages will start with `@apollo/`. This leaves the `apollo-` namespace open for community integration packages (e.g., `apollo-server-fastify`).
+Note that once AS4 is released, all actively maintained Apollo packages will start with `@apollo/`. This leaves the `apollo-` namespace open for community integration packages (e.g., `apollo-server-integration-fastify`).
## Bumped dependencies
@@ -244,7 +244,7 @@ If you're using Node.js 12, upgrade your runtime before upgrading to Apollo Serv
### `graphql`
-Apollo Server has a peer dependency on [`graphql`](https://www.npmjs.com/package/graphql) (the core JS GraphQL implementation). Apollo Server 4 supports `graphql` v16.3.0 and later. (Apollo Server 3 supported `graphql` v15.3.0 through v16.)
+Apollo Server has a peer dependency on [`graphql`](https://www.npmjs.com/package/graphql) (the core JS GraphQL implementation). Apollo Server 4 supports `graphql` v16.5.0 and later. (Apollo Server 3 supported `graphql` v15.3.0 through v16.)
If you're using an older version of `graphql`, upgrade it to a supported version before upgrading to Apollo Server 4.
diff --git a/packages/plugin-response-cache/package.json b/packages/plugin-response-cache/package.json
index 120ad0c11f9..09652699ded 100644
--- a/packages/plugin-response-cache/package.json
+++ b/packages/plugin-response-cache/package.json
@@ -34,6 +34,6 @@
},
"peerDependencies": {
"@apollo/server": "^4.0.0-alpha.0",
- "graphql": "^16.0.0"
+ "graphql": "^16.5.0"
}
}
From d7dc6a86bd74756b60382326bd746760985f8b20 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Thu, 21 Jul 2022 16:24:48 -0700
Subject: [PATCH 15/19] Apply suggestions from code review
Co-authored-by: Rose M Koron <32436232+rkoron007@users.noreply.github.com>
---
docs/source/migration.mdx | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index a505e074ee4..9765adeabac 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -56,7 +56,9 @@ The following sections shows how servers using `apollo-server` and `apollo-serve
### Migrating from `apollo-server`
-If you used the batteries-included `apollo-server` package in Apollo Server 3, you'll want to use the `startStandaloneServer` function in Apollo Server 4. Call `startStandaloneServer(server)` instead of `server.listen()`. Note that you cannot configure CORS settings with `startStandaloneServer`; if you want to change CORS settings from the default, use `expressMiddleware` instead.
+In Apollo Server 3, the `apollo-server` package is a "batteries-included" package that wraps `apollo-server-express`, providing an HTTP server with minimal HTTP-level customization.
+
+If you used the "batteries included" `apollo-server` package in Apollo Server 3, you'll use the `startStandaloneServer` function in Apollo Server 4:
@@ -106,7 +108,9 @@ async function startApolloServer() {
+Note that we start our server using `startStandaloneServer(server)` (instead of calling `server.listen()`).
+> The `startStandaloneServer` function doesn't enable you to configure your server's CORS setting. If you want to customize your CORS settings, use the [`expressMiddleware` function](#migrating-from-apollo-server-express) instead.
### Migrating from `apollo-server-express`
If you used the `apollo-server-express` package in Apollo Server 3, you'll use the `expressMiddleware` function in Apollo Server 4 (instead of using `applyMiddleware`).
From cda126350d205443c141260450e175acf0400672 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Thu, 21 Jul 2022 16:27:53 -0700
Subject: [PATCH 16/19] Follow-up to the previous one
---
docs/source/migration.mdx | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index 9765adeabac..f7aa4c38626 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -56,9 +56,9 @@ The following sections shows how servers using `apollo-server` and `apollo-serve
### Migrating from `apollo-server`
-In Apollo Server 3, the `apollo-server` package is a "batteries-included" package that wraps `apollo-server-express`, providing an HTTP server with minimal HTTP-level customization.
+In Apollo Server 3, the `apollo-server` package is a "batteries-included" package that wraps `apollo-server-express`, providing an HTTP server with minimal HTTP-level customization.
-If you used the "batteries included" `apollo-server` package in Apollo Server 3, you'll use the `startStandaloneServer` function in Apollo Server 4:
+If you used the "batteries included" `apollo-server` package in Apollo Server 3, you'll use the `startStandaloneServer` function in Apollo Server 4 instead of `server.listen()`.
@@ -108,9 +108,11 @@ async function startApolloServer() {
-Note that we start our server using `startStandaloneServer(server)` (instead of calling `server.listen()`).
+The `startStandaloneServer` function doesn't enable you to configure your server's CORS behavior. If you used the `cors` constructor option in Apollo Server 3 to customize your CORS settings, use the [`expressMiddleware` function](#migrating-from-apollo-server-express) instead.
+
+Similarly, if you used the `stopGracePeriodMillis` constructor option in Apollo Server 3, use the [`expressMiddleware` function](#migrating-from-apollo-server-express) and specify `stopGracePeriodMillis` to the `ApolloServerPluginDrainHttpServer` plugin.
+
-> The `startStandaloneServer` function doesn't enable you to configure your server's CORS setting. If you want to customize your CORS settings, use the [`expressMiddleware` function](#migrating-from-apollo-server-express) instead.
### Migrating from `apollo-server-express`
If you used the `apollo-server-express` package in Apollo Server 3, you'll use the `expressMiddleware` function in Apollo Server 4 (instead of using `applyMiddleware`).
From 8ceed8cacb6cfadc646b08a59f37f066dc476663 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Thu, 21 Jul 2022 16:38:39 -0700
Subject: [PATCH 17/19] gateway
---
docs/source/migration.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index f7aa4c38626..4b9e107536b 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -741,7 +741,7 @@ ApolloServerPluginUsageReporting({
### Older Gateway types
-The `gateway` option to the `ApolloServer` constructor is designed to be used with Apollo Gateway, but can also be used with your own implementation of the gateway interface. Several changes have been made to that interface in Apollo Server 4.
+The `gateway` option to the `ApolloServer` constructor is designed for use with the `ApolloGateway` class from the `@apollo/gateway` package. Apollo Server 4 changes the details of how Apollo Server interacts with this object. If you are using a [supported version of `@apollo/gateway`](#apollo-gateway) as your server's `gateway`, the changes will not affect you. However, if you provide something other than an `ApolloGateway` instance to this option, you might need to adjust your custom code.
In Apollo Server 2, the TypeScript type used for the `gateway` constructor option is called `GraphQLService`. In Apollo Server 3, the TypeScript type is called `GatewayInterface`, but the `apollo-server-core` package continued to export an identical `GraphQLService` type as well.
From a0cbd214183e9ad82c6c7ca6434dbc35e60f3c39 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Thu, 21 Jul 2022 16:44:59 -0700
Subject: [PATCH 18/19] as shown above
---
docs/source/migration.mdx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index 4b9e107536b..6f5584d9e95 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -26,7 +26,7 @@ Apollo Server 3 is distributed as a [fixed set of packages](/apollo-server/integ
In Apollo Server 3, the `apollo-server-core` package defines an `ApolloServer` "base" class, which each integration package (e.g., `apollo-server-express`,`apollo-server-lambda`, etc. ) exports as a subclass with the same name and a slightly different API. This packaging structure means that new integration package releases are lockstep versioned to Apollo Server itself, making it challenging to support major versions of frameworks and add integration-specific changes.
-Apollo Server 4 takes a different approach to integrations. Apollo Server 4 has a stable web framework integration API, which includes explicit support for serverless framework life cycles. The new `@apollo/server` package contains the `ApolloServer` class, an [Express 4 integration](#migrating-from-apollo-server-express) (similar to AS3's `apollo-server-express` package), and a [standalone server](#migrating-from-apollo-server) (similar to AS3's `apollo-server` package). There are no subclasses in AS4; there is a single `ApolloServer` class with a single API that all integrations use.
+Apollo Server 4 takes a different approach to integrations. Apollo Server 4 has a stable web framework integration API, which includes explicit support for serverless framework life cycles. The new `@apollo/server` package contains the `ApolloServer` class, an [Express 4 integration](#migrating-from-apollo-server-express) (similar to AS3's `apollo-server-express` package), a [standalone server](#migrating-from-apollo-server) (similar to AS3's `apollo-server` package), and a set of core plugins (similar to AS3's `apollo-server-core` package). There are no subclasses in AS4; there is a single `ApolloServer` class with a single API that all integrations use.
In Apollo Server 3, the Apollo Server core team is responsible for maintaining all integration packages. With Apollo Server 4, the AS core team will stop directly maintaining most integration packages. We will instead work with the broader open source community to maintain Apollo Server integrations, enabling those who regularly use different web frameworks to make the best choices for their framework's integration. If you'd like to help maintain an integration, please [see this issue calling for integration maintainers](https://github.com/apollographql/apollo-server/labels/integration-collaborators).
@@ -216,9 +216,9 @@ In Apollo Server 3, the `apollo-server-express` package supported both Express a
### Packages merged into `@apollo/server`
-As described above, the functionality provided by the `apollo-server-core`, `apollo-server`, and `apollo-server-express` packages in AS3 has been combined into the single `@apollo/server` package in AS4.
+As shown above, Apollo Server 4 combines the functionality of the `apollo-server`, `apollo-server-express`, and `apollo-server-core` packages into a new `@apollo/server` package.
-But wait: there's more! The following packages have *also* been combined into `@apollo/server`:
+But wait: there's more! The `@apollo/server` package also combines the following packages:
- [`apollo-server-errors`](https://www.npmjs.com/package/apollo-server-errors)
- [`apollo-server-plugin-base`](https://www.npmjs.com/package/apollo-server-plugin-base)
- [`apollo-server-types`](https://www.npmjs.com/package/apollo-server-types)
From 96401a1d7a245023d41d703fe16ce25f1074caf4 Mon Sep 17 00:00:00 2001
From: David Glasser
Date: Thu, 21 Jul 2022 16:55:07 -0700
Subject: [PATCH 19/19] context
---
docs/source/migration.mdx | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/docs/source/migration.mdx b/docs/source/migration.mdx
index 6f5584d9e95..861fe7cd117 100644
--- a/docs/source/migration.mdx
+++ b/docs/source/migration.mdx
@@ -1173,11 +1173,9 @@ Several Apollo Server 4 changes only affect TypeScript typings, not runtime beha
### Improved typing for `context`
-In Apollo Server 3, you don't tell TypeScript what type your context value is, so there is no compile-time check that the type returned by your `context` function matches the context value type read by your resolvers and plugins. `ApolloServer` does have a generic parameter, but that parameter is the type of the arguments *passed to* your context function (and is specified by your web integration) rather than your app's context value type.
+In Apollo Server 3, you never specify the type of your context value when setting your server. This means there is no compile-time check that the type `context` function returns matches the type of your context value (read by your resolvers and plugins). `ApolloServer` has a generic parameter, but that parameter is the type of the *arguments passed* to your `context` function , _not_ the type of your app's context value.
-In Apollo Server 4, you can type your `context` by passing an argument to `ApolloServer`'s integration function. This gives you proper `context` typing throughout, providing you with `context` type inference and enabling you to ensure your `context` object is complete before executing requests. (We no longer need a generic parameter for the type of the arguments to the context function, since the context function is passed directly to the framework-specific middleware function such as `expressMiddleware` which can define the correct type directly.)
-
-You can set up `context` TypeScript typing with `ApolloServer`, like so:
+In Apollo Server 4, you specify the type of your context value as a generic parameter to `ApolloServer`. This gives you proper `context` typing throughout, ensuring that the type returned from your `context` function matches the type available in your resolvers and plugins. For example:
```ts
// You can optionally create a TS interface to set up types
@@ -1190,11 +1188,20 @@ interface MyContext {
// context's types to ApolloServer's integration function.
const server = new ApolloServer({
typeDefs,
- resolvers,
- plugins: [
- // Plugins declared to be still work.
- ApolloServerPluginCacheControlDisabled(),
- ],
+ resolvers: {
+ Query: {
+ hello: (root, args, { token }) {
+ return token; // token is properly inferred as a string
+ },
+ },
+ },
+ plugins: [{
+ async requestDidStart({ contextValue }) {
+ // token is properly inferred as a string; note that in AS4 you
+ // write `contextValue` rather than `context` in plugins.
+ console.log(contextValue.token);
+ },
+ }],
});
const { url } = await startStandaloneServer(apolloServerInstance, {