Remote schemas

Generate GraphQL schema objects that delegate to a remote server

It can be valuable to be able to treat remote GraphQL endpoints as if they were local executable schemas. This is especially useful for schema stitching, but there may be other use cases.

Generally, to create a remote schema, you need three steps:

  1. Create a link that can retrieve results from that schema
  2. Use introspectSchema to get the schema of the remote server
  3. Use makeRemoteExecutableSchema to create a schema that uses the link to delegate requests to the underlying service

We’ve chosen to split this functionality up to give you the flexibility to choose when to do the introspection step. For example, you might already have the remote schema information, allowing you to skip the introspectSchema step entirely. Here’s a complete example:

1
2
3
4
5
6
7
8
9
10
11
import { HttpLink } from 'apollo-link-http';
import fetch from 'node-fetch';
const link = new HttpLink({ uri: 'http://api.githunt.com/graphql', fetch });
const schema = await introspectSchema(link);
const executableSchema = makeRemoteExecutableSchema({
schema,
link,
});

Now, let’s look at all the parts separately.

A link is a function capable of retrieving GraphQL results. It is the same way that Apollo Client handles fetching data and is used by several graphql-tools features to do introspection or fetch results during execution. Using an Apollo Link brings with it a large feature set for common use cases. For instance, adding error handling to your request is super easy using the apollo-link-error package. You can set headers, batch requests, and even configure your app to retry on failed attempts all by including new links into your request chain.

Since graphql-tools supports using a link for the network layer, the API is the same as you would write on the client. To learn more about how Apollo Link works, check out the docs; Both GraphQL and Apollo Links have slightly varying concepts of what context is used for. To make it easy to use your GraphQL context to create your Apollo Link context, makeRemoteExecutableSchema attaches the context from the graphql resolver onto the link context under graphqlContext.

Basic usage

1
2
3
4
5
6
7
8
9
10
11
import { HttpLink } from 'apollo-link-http';
import fetch from 'node-fetch';
const link = new HttpLink({ uri: 'http://api.githunt.com/graphql', fetch });
const schema = await introspectSchema(link);
const executableSchema = makeRemoteExecutableSchema({
schema,
link,
});

Authentication headers from context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { HttpLink } from 'apollo-link-http';
import fetch from 'node-fetch';
const http = new HttpLink({ uri: 'http://api.githunt.com/graphql', fetch });
const auth = new ApolloLink((operation, forward) => {
operation.setContext((context) => ({
headers: {
'Authentication': `Bearer ${context.graphqlContext.authKey}`,
},
}))
return forward(operation);
})
const schema = await introspectSchema(link);
const executableSchema = makeRemoteExecutableSchema({
schema,
link,
});


Fetcher API

You can also use a fetcher (like apollo-fetch or node-fetch) instead of a link. A fetcher is a function that takes one argument, an object that describes an operation:

1
2
3
4
5
6
7
8
type Fetcher = (operation: Operation) => Promise<ExecutionResult>;
type Operation {
query: string;
operationName?: string;
variables?: Object;
context?: Object;
}


Using apollo-fetch

Basic usage

1
2
3
4
5
6
7
import { createApolloFetch } from 'apollo-fetch';
const fetcher = createApolloFetch({ uri: 'http://api.githunt.com/graphql'});
const schema = makeRemoteExecutableSchema({
schema: await introspectSchema(fetcher),
fetcher,
});

Authentication headers from context

1
2
3
4
5
6
7
8
9
10
11
12
13
const fetcher = createApolloFetch({ uri: 'http://api.githunt.com/graphql'});
fetcher.use({ request, option }, next) => {
if (!options.headers) {
options.headers = {};
}
options.headers['Authorization'] = `Bearer ${request.context.authKey}`;
next();
});
const schema = makeRemoteExecutableSchema({
schema: await introspectSchema(fetcher),
fetcher,
});


Using node-fetch

Basic usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import fetch from 'node-fetch';
const fetcher = async ({ query, variables, operationName, context }) => {
const fetchResult = fetch('http://api.githunt.com/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ query, variables, operationName })
});
return fetchResult.json();
};
const schema = makeRemoteExecutableSchema({
schema: await introspectSchema(fetcher),
fetcher,
});

Authentication headers from context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import fetch from 'node-fetch';
const fetcher = async ({ query, variables, operationName, context }) => {
const fetchResult = fetch('http://api.githunt.com/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authentication': `Bearer ${context.authKey}`,
},
body: JSON.stringify({ query, variables, operationName })
});
return fetchResult.json();
};
const schema = makeRemoteExecutableSchema({
schema: await introspectSchema(fetcher),
fetcher,
});

API


makeRemoteExecutableSchema(options)

makeExecutableSchema takes a single argument: an object of options. The schema and either a fetcher or a link options are required.

1
2
3
4
5
6
7
import { makeRemoteExecutableSchema } from 'graphql-tools';
const schema = makeRemoteExecutableSchema({
schema,
link,
// fetcher, you can pass a fetcher instead of a link
});

Given a GraphQL.js schema (can be a non-executable client schema made by buildClientSchema) and a Link or Fetcher, produce a GraphQL Schema that routes all requests to the link or fetcher.


introspectSchema(fetcher, [context])

Use link to build a client schema using introspection query. This function makes it easier to use makeRemoteExecutableSchema. As a result, you get a promise to a non-executable GraphQL.js schema object. Accepts optional second argument context, which is passed to the link; see the docs about links above for more details.

1
2
3
4
5
6
7
8
import { introspectSchema } from 'graphql-tools';
introspectSchema(link).then((schema) => {
// use the schema
});
// or, with async/await:
const schema = await introspectSchema(link);
Edit on GitHub