Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gateway support via new @apollo/server-gateway-interface package #6771

Merged
merged 5 commits into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/eleven-needles-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@apollo/server-integration-testsuite": patch
"@apollo/server": patch
---

Support Gateway. Remove executor constructor option.
53 changes: 48 additions & 5 deletions docs/source/migration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ If supporting older versions of TypeScript is important to you and you'd like to

### `@apollo/gateway`

<!-- TODO(AS4): Fix before release -->
<!-- TODO(AS4): Fix before release. This now works at runtime; TS builds may require a new release of Gateway, and we'll update the docs when that's ready. -->

> ⚠️ Note: The alpha version of Apollo Server 4 does **not** work as an [Apollo Gateway](/federation/gateway). You can still use this alpha to serve [subgraphs](/federation/subgraphs), just not Gateways. We will fix this before the general release of Apollo Server 4.

Expand Down Expand Up @@ -741,6 +741,45 @@ new ApolloServer<MyContext>({
});
```

### `executor`

In Apollo Server 3, there are two different ways to specify a replacement for `graphql-js`'s execution functionality. Both of them involve defining a function of the type `GraphQLExecutor`. One way is to specify that function directly as the `executor` constructor option. The other way involves using the `gateway` option.

In Apollo Server 4, this redundancy has been removed: there is no longer an `executor` constructor option. (Additionally, the TypeScript `GraphQLExecutor` type has been renamed `GatewayExecutor` and moved to the `@apollo/server-gateway-interface` package.)

If your Apollo Server 3 code defined an `executor` function and used it like this:

<MultiCodeBlock>

```ts
new ApolloServer({
executor,
// ...
});
```

</MultiCodeBlock>

your Apollo Server code can use `gateway`, like so:

<MultiCodeBlock>

```ts
new ApolloServer({
gateway: {
async load() {
return { executor };
},
onSchemaLoadOrUpdate() {
return () => {};
},
async stop() {},
},
});
```

</MultiCodeBlock>


## Removed features

Expand Down Expand Up @@ -1326,14 +1365,18 @@ Apollo Server 4 more consistently handles errors thrown by multiple plugin hooks

The `gateway` option to the `ApolloServer` constructor is designed to be used 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 use a [supported version of `@apollo/gateway`](#apollo-gateway) as your server's `gateway`, these changes won't 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 changed to `GatewayInterface`, but the `apollo-server-core` package continued to export an identical `GraphQLService` type. Apollo Server 4 no longer exports the legacy `GraphQLService` type. Instead, use `GatewayInterface`.
All the TypeScript types you need to define your `gateway` are now part of the `@apollo/server-gateway-interface` package rather than being exported from an Apollo Server package directly. Additionally, many of these types have been renamed.

In Apollo Server 3, your `gateway` may define either `onSchemaChange` or the newer `onSchemaLoadOrUpdate`. In Apollo Server 4, your `gateway` must define `onSchemaLoadOrUpdate`.
In Apollo Server 2, the TypeScript type used for the `gateway` constructor option is called `GraphQLService`. In Apollo Server 3, the TypeScript type changed to `GatewayInterface`, but the `apollo-server-core` package continued to export an identical `GraphQLService` type. Apollo Server 4 no longer exports the legacy `GraphQLService` type. Instead, use `GatewayInterface`, now exported from `@apollo/server-gateway-interface`.

In Apollo Server 3, the `GatewayInterface.load` method returns `Promise<GraphQLServiceConfig>`, which contains a `schema` and an `executor`. Apollo Server 4 renames `GraphQLServiceConfig` to `GatewayLoadResult`, which now only has an `executor` field. You can use the `onSchemaLoadOrUpdate` hook if you want to receive the schema.
In Apollo Server 3, your `gateway` may define either `onSchemaChange` or the newer `onSchemaLoadOrUpdate`. In Apollo Server 4, your `gateway` must define `onSchemaLoadOrUpdate`.

In Apollo Server 3, `GatewayInterface.load` returned an object with an `executor` field with the TypeScript type `GraphQLExecutor`. The `executor` field returned the `GraphQLExecutionResult` type, a type defined by Apollo Server 3. In Apollo Server 4, the `GraphQLExecutor` type now returns the `ExecutionResult` type from `graphql-js`. These two types are essentially the same, except that in `ExecutionResult` the `data` and `extensions` fields are now `Record<string, unknown>`, rather than `Record<string, any>`.
In Apollo Server 3, the `GatewayInterface.load` method returns `Promise<GraphQLServiceConfig>`, which contains a `schema` and an `executor`. Apollo Server 4 renames `GraphQLServiceConfig` to `GatewayLoadResult` (exported from `@apollo/server-gateway-interface`), which now only has an `executor` field. You can use the `onSchemaLoadOrUpdate` hook if you want to receive the schema.

Additionally, the following types have been renamed and are now exported from `@apollo/server-gateway-interface`:
- `GraphQLExecutor` is now `GatewayExecutor`
- `SchemaLoadOrUpdateCallback` is now `GatewaySchemaLoadOrUpdateCallback`
- `Unsubscriber` is now `GatewayUnsubscriber`


## Changes to defaults
Expand Down
30 changes: 30 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 14 additions & 14 deletions packages/integration-testsuite/src/apolloServerTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,7 @@ import {
import type {
ApolloServerOptions,
ApolloServer,
GatewayInterface,
SchemaLoadOrUpdateCallback,
BaseContext,
GraphQLExecutor,
GraphQLRequestContextExecutionDidStart,
PluginDefinition,
} from '@apollo/server';
import fetch from 'node-fetch';
Expand Down Expand Up @@ -71,6 +67,12 @@ import {
it,
} from '@jest/globals';
import type { Mock } from 'jest-mock';
import type {
GatewayExecutor,
GatewayGraphQLRequestContext,
GatewayInterface,
GatewaySchemaLoadOrUpdateCallback,
} from '@apollo/server-gateway-interface';

const quietLogger = loglevel.getLogger('quiet');
function mockLogger() {
Expand Down Expand Up @@ -122,18 +124,18 @@ const makeGatewayMock = ({
optionsSpy = (_options) => {},
unsubscribeSpy = () => {},
}: {
executor: GraphQLExecutor<BaseContext> | null;
executor: GatewayExecutor | null;
schema: GraphQLSchema;
optionsSpy?: (_options: any) => void;
unsubscribeSpy?: () => void;
}) => {
const triggers = {
// This gets updated later, when ApolloServer calls gateway.load().
triggerSchemaChange: null as SchemaLoadOrUpdateCallback | null,
triggerSchemaChange: null as GatewaySchemaLoadOrUpdateCallback | null,
};

const listeners: SchemaLoadOrUpdateCallback[] = [];
const mockedGateway: GatewayInterface<BaseContext> = {
const listeners: GatewaySchemaLoadOrUpdateCallback[] = [];
const mockedGateway: GatewayInterface = {
load: async (options) => {
optionsSpy(options);
// Make sure it's async
Expand Down Expand Up @@ -459,7 +461,7 @@ export function defineIntegrationTestSuiteApolloServerTests(
});

it("accepts a gateway's schema and calls its executor", async () => {
const executor = jest.fn<GraphQLExecutor<{}>>();
const executor = jest.fn<GatewayExecutor>();
executor.mockReturnValue(
Promise.resolve({ data: { testString: 'hi - but federated!' } }),
);
Expand All @@ -482,7 +484,7 @@ export function defineIntegrationTestSuiteApolloServerTests(
const loadError = new Error(
'load error which should be be thrown by start',
);
const gateway: GatewayInterface<BaseContext> = {
const gateway: GatewayInterface = {
async load() {
throw loadError;
},
Expand Down Expand Up @@ -2247,7 +2249,7 @@ export function defineIntegrationTestSuiteApolloServerTests(
}),
});

const executor = (req: GraphQLRequestContextExecutionDidStart<any>) =>
const executor = (req: GatewayGraphQLRequestContext) =>
(req.source as string).match(/1/)
? Promise.resolve({ data: { testString1: 'hello' } })
: Promise.resolve({ data: { testString2: 'aloha' } });
Expand Down Expand Up @@ -2417,9 +2419,7 @@ export function defineIntegrationTestSuiteApolloServerTests(
};
});

const executor = async (
req: GraphQLRequestContextExecutionDidStart<any>,
) => {
const executor = async (req: GatewayGraphQLRequestContext) => {
const source = req.source as string;
const { startPromise, endPromise, i } = executorData[source];
startPromise.resolve();
Expand Down
4 changes: 3 additions & 1 deletion packages/integration-testsuite/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@
"outDir": "./dist"
},
"include": ["src/**/*"],
"references": [{ "path": "../server" }]
"references": [
{ "path": "../server" },
],
}
1 change: 1 addition & 0 deletions packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
},
"dependencies": {
"@apollo/cache-control-types": "^1.0.2",
"@apollo/server-gateway-interface": "^1.0.0",
"@apollo/usage-reporting-protobuf": "^4.0.0-alpha.1",
"@apollo/utils.createhash": "^1.1.0",
"@apollo/utils.fetcher": "^1.0.0",
Expand Down
Loading