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

[managed-federation] add new plugin to integrate Apollo GraphOS supergraph #3305

Merged
merged 13 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
11 changes: 11 additions & 0 deletions examples/apollo-managed-federation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Apollo Managed Federation Example

Run Apollo Managed Federation supergraph using GraphQL Yoga.

Start Gateway:

```bash
pnpm start
```

Then visit `http://localhost:4000`
19 changes: 19 additions & 0 deletions examples/apollo-managed-federation/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "example-apollo-federation",
"version": "0.0.1",
"private": true,
"scripts": {
"check": "tsc --noEmit --pretty",
"start": "tsx src/index.ts"
},
"dependencies": {
"@graphql-yoga/apollo-managed-federation": "workspace:^",
"graphql-yoga": "workspace:^",
"tsx": "4.11.0"
},
"devDependencies": {
"@graphql-yoga/apollo-managed-federation": "workspace:*",
"graphql-yoga": "workspace:*",
"typescript": "5.4.5"
}
}
17 changes: 17 additions & 0 deletions examples/apollo-managed-federation/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { createServer } from 'node:http';
import { createYoga } from 'graphql-yoga';
import { useManagedFederation } from '@graphql-yoga/apollo-managed-federation';

const yoga = createYoga({
plugins: [useManagedFederation()],
});

const server = createServer(yoga);

server.listen(4000, () => {
console.log('Server is running on http://localhost:4000');
});

process.on('SIGINT', () => {
server.close();
});
44 changes: 44 additions & 0 deletions packages/plugins/apollo-managed-federation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## `@envelop/apollo-managed-federation`

This plugin integrates Apollo Managed Federation into Yoga.

## Installation

First install required dependencies:

```
yarn add graphql-yoga @graphql-yoga/apollo-managed-federation
```

You will also need and API key and the graph ref you want to deploy.

[Please follow this instructions if you don't know where to find this values.](https://www.apollographql.com/docs/federation/v1/managed-federation/setup/#4-connect-the-gateway-to-studio)

## Usage Example

```ts
import { createServer } from 'node:http'
import { createYoga } from 'graphql-yoga'
import { useManagedFederation } from '@graphql-yoga/apollo-managed-federation'

const yoga = createYoga({
plugins: [useManagedFederation()]
})

const server = createServer(yoga)

server.listen(4000, () => {
console.log('Server is running on http://localhost:4000')
})

process.on('SIGINT', () => {
server.close()
})
```

You can then start the gateway, don't forget to provide your API key and graph ref. You can also
provide this values programmatically in plugin options.

```bash
APOLLO_KEY='<YOUR_GRAPH_API_KEY>' APOLLO_GRAPH_REF='<YOUR_GRAPH_ID>@<VARIANT>' node index.mjs
```
73 changes: 73 additions & 0 deletions packages/plugins/apollo-managed-federation/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"name": "@graphql-yoga/apollo-managed-federation",
"version": "0.0.0",
"type": "module",
"repository": {
"type": "git",
"url": "https://github.com/dotansimha/graphql-yoga.git",
"directory": "packages/plugins/apollo-inline-trace"
},
"author": "Valentin Cocaud <v.cocaud@gmail.com>",
"license": "MIT",
"engines": {
"node": ">=18.0.0"
},
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"exports": {
".": {
"require": {
"types": "./dist/typings/index.d.cts",
"default": "./dist/cjs/index.js"
},
"import": {
"types": "./dist/typings/index.d.ts",
"default": "./dist/esm/index.js"
},
"default": {
"types": "./dist/typings/index.d.ts",
"default": "./dist/esm/index.js"
}
},
"./*": {
"require": {
"types": "./dist/typings/*.d.cts",
"default": "./dist/cjs/*.js"
},
"import": {
"types": "./dist/typings/*.d.ts",
"default": "./dist/esm/*.js"
},
"default": {
"types": "./dist/typings/*.d.ts",
"default": "./dist/esm/*.js"
}
},
"./package.json": "./package.json"
},
"typings": "dist/typings/index.d.ts",
"peerDependencies": {
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0",
"graphql-yoga": "workspace:^"
},
"dependencies": {
"@graphql-tools/federation": "1.1.37-alpha-20240603143958-2fcb166e2e4b5d3bf6569caa86a446d5970c9531",
EmrysMyrddin marked this conversation as resolved.
Show resolved Hide resolved
"tslib": "^2.5.0"
},
"devDependencies": {
"graphql": "16.8.1",
"graphql-yoga": "workspace:^",
"typescript": "5.1.3"
},
"publishConfig": {
"directory": "dist",
"access": "public"
},
"sideEffects": false,
"buildOptions": {
"input": "./src/index.ts"
},
"typescript": {
"definition": "dist/typings/index.d.ts"
}
}
39 changes: 39 additions & 0 deletions packages/plugins/apollo-managed-federation/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import type { Plugin } from 'graphql-yoga';
import { SupergraphSchemaManager, SupergraphSchemaManagerOptions } from '@graphql-tools/federation';

export type ManagedFederationPluginOptions = SupergraphSchemaManagerOptions;

export type Logger = {
info: (message: string, ...args: unknown[]) => void;
error: (message: string, error?: unknown, ...args: unknown[]) => void;
};

export function useManagedFederation(options: ManagedFederationPluginOptions = {}): Plugin {
const supergraphManager = new SupergraphSchemaManager(options);

// Start as soon as possible to minimize the wait time of the first schema loading
supergraphManager.start();

const plugin: Plugin = {
onPluginInit({ setSchema }) {
if (supergraphManager.schema) {
setSchema(supergraphManager.schema);
} else {
// Wait for the first schema to be loaded before before allowing requests to be parsed
// We can then remove the onRequestParse hook to avoid async cost on every request
const waitForInitialization = new Promise<void>(resolve => {
supergraphManager.on('schema', () => {
EmrysMyrddin marked this conversation as resolved.
Show resolved Hide resolved
EmrysMyrddin marked this conversation as resolved.
Show resolved Hide resolved
plugin.onRequestParse = undefined;
resolve();
});
});
plugin.onRequestParse = async () => {
await waitForInitialization;
EmrysMyrddin marked this conversation as resolved.
Show resolved Hide resolved
};
}
supergraphManager.on('schema', setSchema);
},
};

return plugin;
}
Loading
Loading