Skip to content

Commit 4bda7be

Browse files
authored
test: apollo-federation example (#1754)
* test: apollo-federation example * make tests work * docs * prettier
1 parent 709969e commit 4bda7be

File tree

7 files changed

+146
-50
lines changed

7 files changed

+146
-50
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { gateway, DataSource } from '../gateway/gateway'
2+
import { yoga as service1 } from '../service/yoga'
3+
import { createServer, Server } from 'http'
4+
import { AddressInfo } from 'net'
5+
import { fetch } from '@whatwg-node/fetch'
6+
import type { GatewayConfig } from '@apollo/gateway'
7+
8+
describe('apollo-federation example integration', () => {
9+
let gatewayServer: Server
10+
let serviceServer: Server
11+
let gatewayPort: number
12+
let servicePort: number
13+
14+
beforeAll(async () => {
15+
serviceServer = createServer(service1)
16+
await new Promise<void>((resolve) => serviceServer.listen(0, resolve))
17+
servicePort = (serviceServer.address() as AddressInfo).port
18+
19+
const gatewayConfig: GatewayConfig = {
20+
serviceList: [
21+
{ name: 'accounts', url: `http://localhost:${servicePort}/graphql` },
22+
],
23+
introspectionHeaders: {
24+
accept: 'application/json',
25+
},
26+
buildService({ url }) {
27+
return new DataSource({ url })
28+
},
29+
}
30+
31+
const gatewayService = await gateway(gatewayConfig)
32+
gatewayServer = createServer(gatewayService)
33+
await new Promise<void>((resolve) => gatewayServer.listen(0, resolve))
34+
gatewayPort = (gatewayServer.address() as AddressInfo).port
35+
})
36+
37+
afterAll(async () => {
38+
await new Promise((resolve) => gatewayServer.close(resolve))
39+
await new Promise((resolve) => serviceServer.close(resolve))
40+
})
41+
42+
it('should execute field on subgraph', async () => {
43+
const response = await fetch(
44+
`http://localhost:${gatewayPort}/graphql?query=query{me { id }}`,
45+
)
46+
const body = await response.json()
47+
expect(body.errors).toBeUndefined()
48+
expect(body.data).toEqual({
49+
me: {
50+
id: '1',
51+
},
52+
})
53+
})
54+
})
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const { createYoga } = require('graphql-yoga')
2+
const { ApolloGateway, RemoteGraphQLDataSource } = require('@apollo/gateway')
3+
const { useApolloFederation } = require('@envelop/apollo-federation')
4+
5+
export async function gateway(config) {
6+
// Initialize the gateway
7+
const gateway = new ApolloGateway(config)
8+
9+
// Make sure all services are loaded
10+
await gateway.load()
11+
12+
const yoga = createYoga({
13+
plugins: [
14+
useApolloFederation({
15+
gateway,
16+
}),
17+
],
18+
})
19+
20+
return yoga
21+
}
22+
23+
/**
24+
* Needed since federation remote data source fetcher
25+
* doesn't support `application/graphql-response+json` content type
26+
* By default Yoga uses `application/graphql-response+json` content type as per the GraphQL over HTTP spec
27+
* https://github.com/apollographql/federation/issues/2161
28+
*/
29+
export class DataSource extends RemoteGraphQLDataSource {
30+
willSendRequest({ request }) {
31+
request.http.headers.set('accept', 'application/json')
32+
}
33+
}

examples/apollo-federation/gateway/index.js

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,15 @@
11
const { createServer } = require('http')
2-
const { createYoga } = require('graphql-yoga')
3-
const { ApolloGateway } = require('@apollo/gateway')
4-
const { useApolloFederation } = require('@envelop/apollo-federation')
2+
const { gateway, DataSource } = require('./gateway')
53

64
async function main() {
7-
// Initialize the gateway
8-
const gateway = new ApolloGateway({
5+
const yoga = gateway({
96
serviceList: [
107
{ name: 'accounts', url: 'http://localhost:4001/graphql' },
118
// ...additional subgraphs...
129
],
13-
})
14-
15-
// Make sure all services are loaded
16-
await gateway.load()
17-
18-
const yoga = createYoga({
19-
plugins: [
20-
useApolloFederation({
21-
gateway,
22-
}),
23-
],
10+
buildService({ url }) {
11+
return new DataSource({ url })
12+
},
2413
})
2514

2615
// Start the server and explore http://localhost:4000/graphql

examples/apollo-federation/service/index.js

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,5 @@
1-
const { parse } = require('graphql')
2-
const { buildSubgraphSchema } = require('@apollo/subgraph')
31
const { createServer } = require('http')
4-
const { createYoga } = require('graphql-yoga')
5-
6-
const typeDefs = parse(/* GraphQL */ `
7-
type Query {
8-
me: User
9-
}
10-
11-
type User @key(fields: "id") {
12-
id: ID!
13-
username: String
14-
}
15-
`)
16-
17-
const resolvers = {
18-
Query: {
19-
me() {
20-
return { id: '1', username: '@ava' }
21-
},
22-
},
23-
User: {
24-
__resolveReference(user, { fetchUserById }) {
25-
return fetchUserById(user.id)
26-
},
27-
},
28-
}
29-
const yoga = createYoga({
30-
schema: buildSubgraphSchema([{ typeDefs, resolvers }]),
31-
})
2+
const { yoga } = require('./yoga')
323

334
const server = createServer(yoga)
345

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const { parse } = require('graphql')
2+
const { buildSubgraphSchema } = require('@apollo/subgraph')
3+
const { createYoga } = require('graphql-yoga')
4+
5+
const typeDefs = parse(/* GraphQL */ `
6+
type Query {
7+
me: User
8+
}
9+
10+
type User @key(fields: "id") {
11+
id: ID!
12+
username: String
13+
}
14+
`)
15+
16+
const resolvers = {
17+
Query: {
18+
me() {
19+
return { id: '1', username: '@ava' }
20+
},
21+
},
22+
User: {
23+
__resolveReference(user, { fetchUserById }) {
24+
return fetchUserById(user.id)
25+
},
26+
},
27+
}
28+
29+
export const yoga = createYoga({
30+
schema: buildSubgraphSchema([{ typeDefs, resolvers }]),
31+
})

website/src/pages/docs/features/apollo-federation.mdx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,34 @@ Thanks to [Envelop's Apollo Federation](https://envelop.dev/plugins/use-apollo-f
3434

3535
```ts
3636
import { createServer } from '@graphql-yoga/node'
37-
import { ApolloGateway } from '@apollo/gateway'
37+
import { ApolloGateway, RemoteGraphQLDataSource } from '@apollo/gateway'
3838
import { useApolloFederation } from '@envelop/apollo-federation'
3939

40+
/**
41+
* Needed since federation remote data source fetcher
42+
* doesn't support `application/graphql-response+json` content type
43+
* https://github.com/apollographql/federation/issues/2161
44+
* And yoga defaults to `application/graphql-response+json` as per the spec.
45+
*/
46+
class DataSource extends RemoteGraphQLDataSource {
47+
willSendRequest({ request }) {
48+
request.http.headers.set('accept', 'application/json')
49+
}
50+
}
51+
4052
// Initialize the gateway
4153
const gateway = new ApolloGateway({
4254
serviceList: [
4355
{ name: 'accounts', url: 'http://localhost:4001' },
4456
{ name: 'products', url: 'http://localhost:4002' },
4557
// ...additional subgraphs...
4658
],
59+
introspectionHeaders: {
60+
accept: 'application/json',
61+
},
62+
buildService({ url }) {
63+
return new DataSource({ url })
64+
},
4765
})
4866

4967
// Make sure all services are loaded

website/src/pages/v3/comparison.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ Apollo Server plans to drop active support for cloudflare workers and [pushes it
2828
GraphQL Yoga will continuously support all platforms and runtimes **wihtout any changes in your code** and
2929
Furthermore, Yoga has a full end to end testing suite that actually deploys to all those runtimes in order to ensure integrity and prevent unexpected issues.
3030

31-
Current list of supported and tested platform:
31+
Current list of supported and tested platform:
3232

3333
Node ([Express](https://www.the-guild.dev/graphql/yoga-server/v3/integrations/integration-with-express), [Fastify](https://www.the-guild.dev/graphql/yoga-server/v3/integrations/integration-with-fastify), [Koa](https://www.the-guild.dev/graphql/yoga-server/v3/integrations/integration-with-koa), [NestJS](https://www.the-guild.dev/graphql/yoga-server/v3/integrations/integration-with-nestjs), [SvelteKit](https://www.the-guild.dev/graphql/yoga-server/v3/integrations/integration-with-sveltekit)), [AWS Lambda](https://www.the-guild.dev/graphql/yoga-server/v3/integrations/integration-with-aws-lambda), [Cloudflare Workers](https://www.the-guild.dev/graphql/yoga-server/v3/integrations/integration-with-cloudflare-workers), [Deno](https://www.the-guild.dev/graphql/yoga-server/v3/integrations/integration-with-deno), [NextJS API Routes](https://www.the-guild.dev/graphql/yoga-server/v3/integrations/integration-with-nextjs), [Bun](https://www.the-guild.dev/graphql/yoga-server/v3/integrations/integration-with-bun) and [more](https://www.the-guild.dev/graphql/yoga-server/v3/integrations/z-other-environments)..
3434

3535
### Powerful Plugin System
3636

37-
GraphQL Yoga is built on top of [Envelop](https://envelop.dev/) - the powerful GraphQL [plugin system](https://www.envelop.dev/plugins).
37+
GraphQL Yoga is built on top of [Envelop](https://envelop.dev/) - the powerful GraphQL [plugin system](https://www.envelop.dev/plugins).
3838

3939
Unfortunately Apollo Server is not fully compatible with it, there is still no further follow-up from the apollo maintainers over [on the Apollo Server and envelop discussion](https://github.com/apollographql/apollo-server/discussions/5541).
4040

@@ -85,7 +85,7 @@ GraphQL Yoga has significantly less latency and much higher requests rate than A
8585

8686
### GraphiQL
8787

88-
While Apollo Server is shipping with their proprietary and less updated hosted IDE and removed the default open source GraphiQL,
88+
While Apollo Server is shipping with their proprietary and less updated hosted IDE and removed the default open source GraphiQL,
8989
GraphQL Yoga ships with the latest and greatest from the open source, Foundation backed [GraphiQL IDE](https://github.com/graphql/graphiql) and we support and contribute to the project.
9090

9191
### Compatibility with Apollo Federation

0 commit comments

Comments
 (0)