Remote Subschemas & Executors
Remote Subschemas & Executors — Schema Stitching documentation.
Remote subschemas are the objects containing a non-executable GraphQLSchema instance and an
Executor function that takes an object including the details for a GraphQL request. Usually this
executor is a function that uses HTTP to receive an ExecutionResult from the service.
Configuring Subschemas
In the example above, the extra “subschema” wrapper objects may look verbose at first glance, but
they are basic implementations of the SubschemaConfig interface that accepts several additional
settings (discussed throughout this guide):
Subschema config should directly provide as many settings as possible to avoid unnecessary layers
of delegation. For example, while we could pre-wrap a subschema with transforms and a remote
executor, that would be far less efficient than providing the schema, transforms, and executor
options directly to subschema config.
Also note that these subschema config objects may need to be referenced again in other stitching contexts, such as schema extensions. With that in mind, you may want to export your subschema configs from their module(s).
batchflag enables Batch Execution
Remote Subschemas via HTTP
To include a remote schema in the combined gateway, you must provide at least the schema and
executor subschema config options.
schema: this is a non-executable schema representing the remote API. The remote schema may be obtained using introspection, or fetched as a flat SDL string (from a server or repo) and built into a schema usingbuildSchema. Note that not all GraphQL servers enable introspection, and those that do will not include custom directives.executor: is a generic method that performs requests to a remote schema. It’s quite simple to write your own. Subschema config uses the executor for query and mutation operations. See handbook example.
Executors
You can use ready-to-use executors from GraphQL Tools or write your own.
Executors are not responsible of validating the requests. By default, the validation is expected to be done on the gateway level based on the gateway request, because the remote APIs should already do the validation. However, if you still want to validate the request on the subschema level, you can use the
validateRequestoption of the subschema configuration objects.
HTTP Executor (@graphql-tools/executor-http)
This package allows you to create an executor for your HTTP service with the following features:
- GraphQL over HTTP protocol for queries and mutations
- Server-sent events as a response type for subscriptions just like GraphQL Yoga implementing it
- GraphQL over Server-Sent Events protocol for subscriptions in a distinct connection mode.
- GraphQL multipart request specification for file uploads and all other types of multipart requests
- RFC: GraphQL Defer and Stream Directives for incremental delivery
- Different fetch strategies like
timeoutandretry
Dynamic Headers and Endpoint URL
It is possible to change headers and endpoint URL dynamically. HTTP executor respects extensions
object passed in the request.
GraphQL over WebSocket Protocol Executor (@graphql-tools/executor-graphql-ws)
This package allows you to create an executor for the service that supports GraphQL over WebSocket protocol. WebSockets are usually used for subscriptions or permanent connection for queries and mutations in case of a heavy traffic.
Combining WS and HTTP executors to use WS only for subscriptions
Creating a custom executor
You can use an executor with any fetching algorithm that takes an ExecutorRequest and returns
ExecutionResult. 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.
Create a custom HTTP executor using Fetch
Create a hybrid executor to use WS for subscriptions
Sometimes you only want to do subscription operations over WebSocket. In that case, you have identified the operation and then call the corresponding executor for the operation type.
With this executor query and mutation operations will be executed over HTTP (using
@whatwg-node/fetch) and subscription operations will be executed via WebSocket (using
graphql-ws).
Introspecting Schemas using Executors
If you don’t have the schema definitions as a URL or a local file, you can introspect the endpoint
to fetch the schema. After creating an executor, you can use schemaFromExecutor to fetch the
schema.
Batch Execution
Batch execution is a technique for consolidating multiple operations that target a single schema. Rather than executing each operation individually, all operations can be combined and executed as one.
For example, given the following GraphQL operations:
These can be merged into one operation, and the resulting data can be unpacked into the original shape of the multiple requests:
Batch execution is useful because:
- Multiple operations can be combined into one network request when targeting remote services.
- Combined operations are guaranteed to multiplex, even with servers that execute incoming requests serially.
- Smaller and more granular GraphQL queries may be composed and cached individually, and then batched. This offers a strategy for sub-request caching.
Batch the Executor (Query Batching)
Once you have an executor for your service, you may call it directly or wrap it with a batch
executor using the createBatchingExecutor method from @graphql-tools/batch-execute:
Remember you don’t need to create a batch executor using this method specifically, a subschema configuration can have
batch: trueflag instead.
When using a batch executor, remember that multiple calls must be performed synchronously and all results awaited as one. Awaiting the results of each batching call individually will behave like a normal executor.
Merging Algorithm
Batch merging uses several transformations to build a request:
- Replace root-level fragment spreads with inline fragments.
- Add uniquely prefixed aliases to all root-level fields.
- Uniquely prefix all variable definitions and their references.
- Uniquely prefix all fragment definitions and their spreads.
- Prune orphaned fragment definitions.
The results are then extracted with a series of reversals:
- Redistribute prefixed fields among original requests.
- Restore original root field aliases.
- Redistribute errors among their corresponding requests.
You can see this example that demonstrates the difference between batch execution and regular execution