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.
There two ways to create remote schemas;
Check out Schema Loading to load schemas from an URL and/or different sources easily without implementing an executor or subscriber.
Generally, to create a remote schema, you generally need just three steps:
- Create a executor that can retrieve results from that schema
introspectSchemato get the non-executable schema of the remote server
wrapSchemato create a schema that uses the executor to delegate requests to the underlying service
You can optionally also include a subscriber that can retrieve real time subscription results from the remote schema (only if you are using GraphQL Subscriptions)
You can use an executor with an HTTP Client implementation (like cross-fetch). An executor is a function capable of retrieving GraphQL results. It is the same way that a GraphQL Client handles fetching data and is used by several
graphql-tools features to do introspection or fetch results during execution.
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:
Authentication headers from context
For subscriptions, we need to define a subscriber that returns
AsyncIterator. Other than that, it has the similar API with
executor to obtain a non-executable client schema from a remote schema using a full introspection query.
introspectSchema is used to acquire the non-executable form of a remote schema that must be passed to
wrapSchema. It returns a promise to a non-executable GraphQL.js schema object. Accepts optional second argument
context, which is passed to the executor; see the docs about executors above for more details.
wrapSchema comes most in handy when wrapping a remote schema. When using the function to wrap a remote schema, it takes a single object: an subschema configuration object with properties describing how the schema should be accessed and wrapped. The
executor options are required.
Transforms are further described within the general schema wrapping section. When using a schema configuration object, transforms should be placed as a property within the configuration, rather than as a separate argument to
Batching and caching can be accomplished by specifying customized executors that manage this for you. We export a
linkToExecutor function in
@graphql-tools/links package that can be used to transform the
HTTPLinkDataloader Apollo-style link (created by Prisma) that will batch and cache all requests. Per request caching is a simple add-on, as the
executor function is provided the context, so a global
executor specified by wrapSchema can simply forward all arguments to a request-specific
executor provided on the context.
For users who need to customize the root proxying resolvers at the time that the wrapping schema is generated, you can also specify a custom
createProxyingResolver function that will create your own root resolvers for the new outer, wrapping schema. This function has the following signature:
You may not need all the options to accomplish what you need. For example, the default proxying resolver creator just uses a subset of the passed arguments, with the fieldName inferred:
Parenthetically, note that that
args from the root field resolver are not directly passed to the target schema. These arguments have already been parsed into their corresponding internal values by the GraphQL execution algorithm. The correct, serialized form of the arguments are available within the
info object, ready for proxying. Specifying the
args property for
delegateToSchema allows one to pass additional arguments to the target schema, which is not necessary when creating a simple proxying schema.
The above can can all be put together like this:
Note that within the
subscriber functions stored on the subschema config object originally passed to
wrapSchema. As above, use of the the
createProxyingResolver option is helpful when you want to customize additional functionality at resolver creation time. If you just want to customize how things are proxied at the time that they are proxied, you can make do just with custom executors and subscribers.
makeRemoteExecutableSchema, the function used in older versions to access remote schemas? It still works -- just now under the hood calling
wrapSchema. There is essentially no longer any need to use
makeRemoteExecutableSchema directly, but we've kept it around for backwards compatibility.
You can still pass a
createResolver function to
makeRemoteExecutableSchema to override how the fetch resolvers are created and executed. The
createResolver param accepts an
Executor as its first argument (and a
Subscriber as its second) and returns a resolver function. This opens up the possibility for users to create batching mechanisms for fetches. As above, it is likely easier to just customize the
executor function itself.
Given a GraphQL.js schema (can be a non-executable client schema made by
buildClientSchema) and a executor,
makeRemoteExecutableSchema produce a GraphQL Schema that routes all requests to the executor: