Skip to content

Commit

Permalink
Merge branch 'next' into clenfest/supergraph_versioning
Browse files Browse the repository at this point in the history
  • Loading branch information
clenfest authored Jun 4, 2023
2 parents 0359c9a + 3798809 commit cfdd354
Show file tree
Hide file tree
Showing 41 changed files with 1,845 additions and 668 deletions.
9 changes: 9 additions & 0 deletions .changeset/giant-olives-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@apollo/gateway": minor
---

Support responses from subgraphs which use the `application/graphql-response+json` content-type header.

See graphql-over-http spec for more details:
https://graphql.github.io/graphql-over-http/draft/#sec-application-graphql-response-json

19 changes: 19 additions & 0 deletions composition-js/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# CHANGELOG for `@apollo/composition`

## 2.4.7
### Patch Changes


- Re-work the code use to try to reuse query named fragments to improve performance (thus sometimes improving query ([#2604](https://github.com/apollographql/federation/pull/2604))
planning performance), to fix a possibly raised assertion error (with a message of form like `Cannot add selection of
field X to selection set of parent type Y`), and to fix a rare issue where an interface or union field was not being
queried for all the types it should be.
- Updated dependencies [[`2d44f346`](https://github.com/apollographql/federation/commit/2d44f346c553f489d83f1c672e1ad8715665cde2)]:
- @apollo/federation-internals@2.4.7
- @apollo/query-graphs@2.4.7

## 2.4.6
### Patch Changes

- Updated dependencies [[`5cd17e69`](https://github.com/apollographql/federation/commit/5cd17e6965664768c9d9f5b734634764bbebf2e7), [`e136ad87`](https://github.com/apollographql/federation/commit/e136ad87db6005ddd8100f98022a043c0846f38e)]:
- @apollo/federation-internals@2.4.6
- @apollo/query-graphs@2.4.6

## 2.4.5
### Patch Changes

Expand Down
6 changes: 3 additions & 3 deletions composition-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@apollo/composition",
"version": "2.4.5",
"version": "2.4.7",
"description": "Apollo Federation composition utilities",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -27,8 +27,8 @@
"access": "public"
},
"dependencies": {
"@apollo/federation-internals": "2.4.5",
"@apollo/query-graphs": "2.4.5"
"@apollo/federation-internals": "2.4.7",
"@apollo/query-graphs": "2.4.7"
},
"peerDependencies": {
"graphql": "^16.5.0"
Expand Down
2 changes: 1 addition & 1 deletion composition-js/src/hints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function makeCodeDefinition({
level: { value: level, name: HintLevel[level]},
description,
});
};
}

const INCONSISTENT_BUT_COMPATIBLE_FIELD_TYPE = makeCodeDefinition({
code: 'INCONSISTENT_BUT_COMPATIBLE_FIELD_TYPE',
Expand Down
2 changes: 1 addition & 1 deletion composition-js/src/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ function buildWitnessOperation(witness: RootPath<Transition>): Operation {
schema,
root.rootKind,
buildWitnessNextStep([...witness].map(e => e[0]), 0)!,
new VariableDefinitions()
new VariableDefinitions(),
);
}

Expand Down
4 changes: 2 additions & 2 deletions docs/source/entities-advanced.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ In any subgraph where you use `@override`, make sure to include it in your schem

```graphql {3} title="Billing subgraph"
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.3",
import: ["@key", "@shareable", "@override"])
@link(url: "https://specs.apollo.dev/federation/v2.3",
import: ["@key", "@shareable", "@override"])
```

</blockquote>
Expand Down
6 changes: 3 additions & 3 deletions docs/source/managed-federation/federated-schema-checks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Federated schema checks
---

> For an introduction to schema checks, see [Schema checks](https://www.apollographql.com/docs/studio/schema-checks/).
> For an introduction to schema checks, see [Schema checks](/graphos/delivery/schema-checks/).
Whenever you make changes to a subgraph schema, running `rover subgraph check` helps ensure that _all_ your subgraph schemas still compose to a valid supergraph schema. This helps teams work independently on their portion of your federated graph without negatively affecting your users or other teams.

Expand All @@ -22,7 +22,7 @@ There are two types of failures that can occur during validation: failed usage c

In _most_ cases, you should run `rover subgraph publish` only after a successful run of `rover subgraph check`. However, certain workflows require intentionally publishing a subgraph schema that fails composition (such as [migrating an entity or field between subgraphs](../entities-advanced/#migrating-entities-and-fields)).

Even after `rover subgraph check` succeeds, however, it's possible that `rover subgraph publish` encounters composition errors because of simultaneous changes to _another_ subgraph. When this occurs, your subgraph's registered schema is still updated as long as it is spec-compliant. However, **the supergraph schema is not updated**. This means that your gateway's configuration is _also_ not updated.
Even after `rover subgraph check` succeeds, however, it's possible that `rover subgraph publish` encounters composition errors because of simultaneous changes to _another_ subgraph. When this occurs, your subgraph's registered schema is still updated as long as it is spec-compliant. However, **the supergraph schema is not updated**. This means that your router's configuration is _also_ not updated.

An example output of this behavior looks like this:

Expand All @@ -41,4 +41,4 @@ There can be only one type named "Book".

The reasoning behind this functionality is that the Apollo schema registry should always reflect what is running in your infrastructure. Even if that means that composition is failing in your infrastructure, the registry should reflect that.

However, you still want your gateway to function as it was before the most recent deployment. Additionally, this functionality can be used to make dependent changes, like smoothly migrating a field from one subgraph to another or introducing a circular dependency.
However, you still want your router to function as it was before the most recent deployment. Additionally, this functionality can be used to make dependent changes, like smoothly migrating a field from one subgraph to another or introducing a circular dependency.
8 changes: 4 additions & 4 deletions docs/source/managed-federation/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ On composition success, GraphOS updates your supergraph's latest configuration,
```mermaid
graph LR;
subgraph "Your infrastructure"
serviceA[Products subgraph];
serviceB[Reviews subgraph];
serviceA[Products<br/>subgraph];
serviceB[Reviews<br/>subgraph];
router([Router]);
end
subgraph "Apollo GraphOS"
registry{{Schema Registry}};
uplink{{Uplink}}
registry{{Apollo Schema<br/>Registry}};
uplink{{Apollo<br/>Uplink}}
end
serviceA & serviceB -->|Publishes<br/>schema| registry;
registry -->|Updates<br/>config| uplink;
Expand Down
99 changes: 73 additions & 26 deletions docs/source/managed-federation/setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,65 @@ title: Setting up managed federation
---

import ObtainGraphApiKey from '../../shared/obtain-graph-api-key.mdx';
import RegisterFederatedCli from '../../shared/register-federated-cli.mdx';

This article describes how to set up Apollo Studio for a graph that uses Apollo Federation.
This article describes how to connect your supergraph to [Apollo GraphOS](/graphos/) to enable managed federation features.

> As with all changes, you should first set up managed federation in a non-production environment, such as staging. To support this, you can use [variants](https://www.apollographql.com/docs/studio/schema/registry/#managing-environments-with-variants), which are distinct versions of the same graph for different environments.
> As with all changes, you should first set up managed federation in a non-production environment, such as staging. To support this, you can create multiple [variants](/graphos/graphs/#variants) of your supergraph in GraphOS Studio. Each variant represents a distinct version of the same graph for different environments.
## 1. Get started

If you haven't yet, complete the first two steps from the Apollo Studio getting started guide:
First, complete the **Set up Apollo tools** step from [this tutorial](/graphos/quickstart/self-hosted#1-set-up-apollo-tools), including:

1. [Create your account](https://www.apollographql.com/docs/studio/getting-started/#1-create-your-account)
2. [Create your first graph](https://www.apollographql.com/docs/studio/getting-started/#2-create-your-first-graph)
- Creating an Apollo account
- Creating a graph in Studio
- Installing and authenticating the Rover CLI

> In the [Register your schema](https://www.apollographql.com/docs/studio/getting-started/#3-register-your-schema) step, make sure you follow the instructions for a GraphQL server that uses Apollo Federation.
Then return here.

## 2. Register all subgraph schemas
## 2. Publish all subgraph schemas

<RegisterFederatedCli />
In a supergraph architecture, each of your [subgraphs](../building-supergraphs/subgraphs-overview/) uses the Rover CLI to publish its schema to GraphOS:

## 3. Modify the gateway (if necessary)
```mermaid
graph LR;
subgraph " "
router([Router]);
subgraphA[Products subgraph];
subgraphB[Reviews subgraph];
subgraphC[Inventory subgraph];
end
registry{{GraphOS<br/>Schema Registry}};
router --- subgraphA & subgraphB & subgraphC;
subgraphA & subgraphB & subgraphC -.->|<code>rover subgraph publish</code>| registry;
class registry secondary;
```

**Do the following for each of your subgraphs**:

1. Obtain the following values, which are required for the `rover subgraph publish` command:

* The name that uniquely identifies the subgraph within your graph (e.g., `products`).
* The URL that your router will use to communicate with the subgraph (e.g., `http://products-graphql.svc.cluster.local:4001/`).

2. Run the `rover subgraph publish` command, providing it your subgraph's schema in one of the ways shown:

```bash
# Provide a local .graphql file path
rover subgraph publish my-graph@my-variant --name products --routing-url http://products-graphql.svc.cluster.local:4001/ --schema ./schema.graphql

# Provide an introspection result via stdin
rover subgraph introspect http://localhost:4000 | rover subgraph publish my-graph@my-variant --name products --routing-url http://products-graphql.svc.cluster.local:4001/ --schema -
```

As you register your subgraph schemas, the schema registry attempts to **compose** their latest versions into a single **supergraph schema**. Whenever composition succeeds, your managed router can fetch the latest supergraph schema from GraphOS.

You can also manually fetch your latest supergraph schema with the `rover supergraph fetch` command, or retrieve it from your graph's **Schema > SDL** tab in GraphOS Studio.

## 3. Modify your router's startup command

> This section assumes you are using Apollo Server with the `@apollo/gateway` library as your gateway.
<ExpansionPanel title="Using Apollo Gateway?">

If you've already set up Apollo Federation _without_ Apollo Studio, the constructor of your `ApolloGateway` instance probably includes a `supergraphSdl` option, like this:
If you've already set up Apollo Federation _without_ connecting your gateway to GraphOS, the constructor of your `ApolloGateway` instance probably includes a `supergraphSdl` option, like this:

```js {2}
const gateway = new ApolloGateway({
Expand All @@ -36,35 +71,47 @@ const gateway = new ApolloGateway({

This option is specific to _non_-managed federation, in which supergraph schema composition is performed via the Rover CLI.

With managed federation, composition is instead performed by _Apollo_, and the gateway regularly polls Apollo for an updated schema. This enables you to add, remove, and modify your subgraphs _without_ needing to restart your gateway.
With managed federation, composition is instead performed by _GraphOS_, and the gateway regularly polls for an updated schema. This enables you to add, remove, and modify your subgraphs _without_ needing to restart your gateway.

Remove the `supergraphSdl` argument from your `ApolloGateway` constructor entirely:

```js
const gateway = new ApolloGateway();
```

## 4. Connect the gateway to Studio
> When running your gateway in an environment where outbound traffic to the internet is restricted, consult the [directions for configuring a proxy](/apollo-server/security/proxy-configuration) within Apollo Server.
Like your subgraphs, your gateway uses a graph API key to identify itself to Studio.
</ExpansionPanel>

<ObtainGraphApiKey />
If you've already set up Apollo Federation _without_ connecting your router to GraphOS, you're probably passing the `--supergraph` (or `-s`) option to the Apollo Router's startup command:

```sh
./router --config ./router.yaml --supergraph ./your-local-supergraph.graphql
```

The `--supergraph` option is specific to _non_-managed federation, in which supergraph schema composition is performed via the Rover CLI and provided via a file path.

After obtaining your graph API key, you set two environment variables in your gateway's environment. If you're using a `.env` file with a library like [`dotenv`](https://www.npmjs.com/package/dotenv), those environment variables look like this:
_Remove_ the `--supergraph` option (but leave `--config` if it's present):

```sh title=".env"
APOLLO_KEY=<YOUR_GRAPH_API_KEY>
APOLLO_GRAPH_REF=<YOUR_GRAPH_ID>@<VARIANT>
```sh
./router --config ./router.yaml
```

You can also set this value directly in the command you use to start your gateway.
> With managed federation, composition is instead performed by _GraphOS_, and the router regularly polls for an updated schema. This enables you to add, remove, and modify your subgraphs _without_ needing to restart your router.
The `APOLLO_GRAPH_REF` environment variable tells the gateway which variant of which graph to use (for example, `my-graph-id@production`). You can find your variant's graph ref at the very top of its README page in Studio.

> When running your gateway in an environment where outbound traffic to the internet is restricted, consult the [directions for configuring a proxy](/apollo-server/security/proxy-configuration) within Apollo Server.
## 4. Connect your router to GraphOS

Like your subgraphs, your router uses a graph API key to identify itself to GraphOS.

<ObtainGraphApiKey />

After obtaining your graph API key, you set the following environment variables in your router's environment:

## 5. Deploy the modified gateway
- `APOLLO_KEY` (set this to your graph API key)
- `APOLLO_GRAPH_REF`
- This variable tells the router which variant of which graph to use (for example, `docs-example-graph@production`). You can find your variant's graph ref at the very top of its README page in GraphOS Studio.

You can now deploy your modified gateway to begin fetching your federated schema from Studio instead of directly from your subgraphs.
## 5. Deploy the modified router

On startup, your gateway will use its API key to fetch its federation config from Apollo. It can then begin executing operations across your subgraphs.
You can now deploy your modified router, which will fetch its supergraph schema from GraphOS on startup. It can then begin executing operations across your subgraphs.
4 changes: 4 additions & 0 deletions federation-integration-testsuite-js/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG for `federation-integration-testsuite-js`

## 2.4.7

## 2.4.6

## 2.4.5
### Patch Changes

Expand Down
2 changes: 1 addition & 1 deletion federation-integration-testsuite-js/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "apollo-federation-integration-testsuite",
"private": true,
"version": "2.4.5",
"version": "2.4.7",
"description": "Apollo Federation Integrations / Test Fixtures",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
21 changes: 21 additions & 0 deletions gateway-js/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# CHANGELOG for `@apollo/gateway`

## 2.4.7
### Patch Changes


- Re-work the code use to try to reuse query named fragments to improve performance (thus sometimes improving query ([#2604](https://github.com/apollographql/federation/pull/2604))
planning performance), to fix a possibly raised assertion error (with a message of form like `Cannot add selection of
field X to selection set of parent type Y`), and to fix a rare issue where an interface or union field was not being
queried for all the types it should be.
- Updated dependencies [[`2d44f346`](https://github.com/apollographql/federation/commit/2d44f346c553f489d83f1c672e1ad8715665cde2)]:
- @apollo/query-planner@2.4.7
- @apollo/composition@2.4.7
- @apollo/federation-internals@2.4.7

## 2.4.6
### Patch Changes

- Updated dependencies [[`5cd17e69`](https://github.com/apollographql/federation/commit/5cd17e6965664768c9d9f5b734634764bbebf2e7), [`8ca107ac`](https://github.com/apollographql/federation/commit/8ca107ac2f19dde5cb64844355a0f7a5296b9008), [`e136ad87`](https://github.com/apollographql/federation/commit/e136ad87db6005ddd8100f98022a043c0846f38e)]:
- @apollo/query-planner@2.4.6
- @apollo/federation-internals@2.4.6
- @apollo/composition@2.4.6

## 2.4.5
### Patch Changes

Expand Down
8 changes: 4 additions & 4 deletions gateway-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@apollo/gateway",
"version": "2.4.5",
"version": "2.4.7",
"description": "Apollo Gateway",
"author": "Apollo <[email protected]>",
"main": "dist/index.js",
Expand All @@ -25,9 +25,9 @@
"access": "public"
},
"dependencies": {
"@apollo/composition": "2.4.5",
"@apollo/federation-internals": "2.4.5",
"@apollo/query-planner": "2.4.5",
"@apollo/composition": "2.4.7",
"@apollo/federation-internals": "2.4.7",
"@apollo/query-planner": "2.4.7",
"@apollo/server-gateway-interface": "^1.1.0",
"@apollo/usage-reporting-protobuf": "^4.1.0",
"@apollo/utils.createhash": "^2.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function getRootQueryFields(schema?: GraphQLSchema): string[] {
let logger: Logger;
let gateway: ApolloGateway | null = null;
let cleanUp: (() => void) | null = null;
let originalMinPollInterval = UplinkSupergraphManager.MIN_POLL_INTERVAL_MS;
const originalMinPollInterval = UplinkSupergraphManager.MIN_POLL_INTERVAL_MS;

beforeEach(() => {
// Set the min poll interval artificially low so we're not waiting during tests
Expand Down
2 changes: 1 addition & 1 deletion gateway-js/src/__tests__/nockAssertions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ export function nockAfterEach() {
nock.restore();
// effectively nock.isDone() but with more helpful messages in test failures
expect(nock.activeMocks()).toEqual([]);
};
}
6 changes: 5 additions & 1 deletion gateway-js/src/datasources/RemoteGraphQLDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,11 @@ export class RemoteGraphQLDataSource<
_context?: TContext,
): Promise<object | string> {
const contentType = fetchResponse.headers.get('Content-Type');
if (contentType && contentType.startsWith('application/json')) {
if (
contentType &&
(contentType.startsWith('application/json') ||
contentType.startsWith('application/graphql-response+json'))
) {
return fetchResponse.json();
} else {
return fetchResponse.text();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,24 @@ describe('constructing requests', () => {
});
});
});

it('stringifies a request with `application/graphql-response+json` content type', async () => {
const DataSource = new RemoteGraphQLDataSource({
url: 'https://api.example.com/foo',
apq: false,
});

nock('https://api.example.com')
.post('/foo', { query: '{ me { name } }' })
.reply(200, { data: { me: 'james' } }, {'content-type': 'application/graphql-response+json'});

const { data } = await DataSource.process({
...defaultProcessOptions,
request: { query: '{ me { name } }' },
});

expect(data).toEqual({ me: 'james' });
});
});

describe('fetcher', () => {
Expand Down
2 changes: 1 addition & 1 deletion gateway-js/src/executeQueryPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ export async function executeQueryPlan(
input: unfilteredData,
introspectionHandling: (f) => executeIntrospection(
operationContext.schema,
f.expandAllFragments().toSelectionNode(),
f.expandFragments().toSelectionNode(),
operationContext.operation.variableDefinitions,
variables,
),
Expand Down
Loading

0 comments on commit cfdd354

Please sign in to comment.