# GraphQL Schema Stitching explained: Schema Delegation URL: https://www.prisma.io/blog/graphql-schema-stitching-explained-schema-delegation-4c6caf468405 Published: 2017-12-12 Authors: Nikolas Burk Description: Understand GraphQL schema delegation and how schema stitching combines multiple services into a unified GraphQL API. > Blog posts describe Prisma as it was on the date shown and are not kept current. Before implementing from a post, check the documentation index at https://www.prisma.io/docs/llms.txt and the changelog at https://www.prisma.io/changelog.md. > For an index of every published post, fetch https://www.prisma.io/blog/llms.txt. Understanding GraphQL schema stitching (Part II) In the [last article](https://www.prisma.io/blog/how-do-graphql-remote-schemas-work-7118237c89d7), we discussed the ins and outs of remote (executable) schemas. These remote schemas are the foundation for a set of tools and techniques referred to as *schema stitching*. Schema stitching is a brand new topic in the GraphQL community. In general, it refers to the act of combining and connecting multiple GraphQL schemas (or [*schema definitions*](https://www.prisma.io/blog/how-do-graphql-remote-schemas-work-7118237c89d7#recap-graphql-schemas)) to create a single GraphQL API. There are two major concepts in schema stitching: * **Schema delegation**: The core idea of schema delegation is to forward (*delegate*) the invocation of a specific resolver to another resolver. In essence, the respective fields of the schema definitions are being “rewired”. * **Schema merging**: Schema merging is the idea of creating the *union* of two (or more) existing GraphQL APIs. This is not problematic if the involved schemas are entirely disjunct — if they are not, there needs to be a way for resolving their naming conflicts. Notice that in most cases, delegation and merging will actually be used together and we’ll end up with a **hybrid approach that uses both**. In this article series, we’ll cover them separately to make sure each concept can be well understood by itself. ## Example: Building a custom GitHub API [#example-building-a-custom-github-api] Let’s start with an example based on the public [GitHub GraphQL API](https://developer.github.com/v4/). Assume we want to build a small app that provides information about the [Prisma GitHub organization](https://github.com/prismagraphql). The API we need for the app should expose the following capabilities: * retrieve information about the Prisma organization (like its *ID*, *email* *address*, *avatar URL* or the *pinned repositories*) * retrieve a list of repositories from the Prisma organization by their names * retrieve a short description about the app itself Let’s explore the [`Query`](https://gist.github.com/gc-codesnippets/a54ab279f6ea181f13a01a232f1aa958#file-github-graphql-L4598) type from [GitHub’s GraphQL schema definition](https://gist.github.com/gc-codesnippets/a54ab279f6ea181f13a01a232f1aa958#file-github-graphql-L4598) to see how we can map our requirements to the schema’s root fields. ### Requirement 1: Retrieve info about Graphcool organization [#requirement-1-retrieve-info-about-graphcool-organization] The first feature, retrieving information about the Prisma organization, can be achieved by using the `repositoryOwner` root field on the `Query` type: ```graphql type Query { # ... # Lookup a repository owner (ie. either a User or an Organization) by login. repositoryOwner( # The username to lookup the owner by. login: String! ): RepositoryOwner # ... } ``` We can send the following query to ask for information about the Prisma organization: ```graphql query { repositoryOwner(login: "prismagraphql") { id url pinnedRepositories(first: 100) { edges { node { name } } } # ask for more data here } } ``` It works when we provide `"prismagraphql"` as the `login` to the `repositoryOwner` field. One issue here is that we can’t ask for the `email` in a straightforward way, because [`RepositoryOwner`](https://gist.github.com/gc-codesnippets/a54ab279f6ea181f13a01a232f1aa958#file-github-graphql-L6161) is only an interface that doesn’t have an `email` field. However, since we know that the concrete type of the Prisma organization is indeed [`Organization`](https://gist.github.com/gc-codesnippets/a54ab279f6ea181f13a01a232f1aa958#file-github-graphql-L3005), we can work around this issue by using an [*inline fragment*](http://graphql.org/learn/queries/#inline-fragments) inside the query: ```graphql query { repositoryOwner(login: "prismagraphql") { id ... on Organization { email } } } ``` Ok, so this will work but we’re already hitting some friction points that don’t allow for a straightforward use of the GitHub GraphQL API for the purpose of our app. Ideally, our API would just expose a root field that allowed to ask directly for the info we want without needing to provide an argument upon every query and letting us ask for fields on `Organization` directly: ```graphql type Query { prismagraphql: Organization! } ``` ### Requirement 2: Retrieve list of Graphcool repositories by name [#requirement-2-retrieve-list-of-graphcool-repositories-by-name] How about the second requirement, retrieving a list of the Graphcool repositories by their names. Looking at the `Query` type again, this becomes a bit more complicated. The API doesn’t allow to retrieve a list of repositories directly— instead you can ask for single repositories by providing the `owner` and the repo’s `name` using the following root field: ```graphql type Query { # ... # Lookup a given repository by the owner and repository name. repository( # The login field of a user or organization owner: String! # The name of the repository name: String! ): Repository # ... } ``` Here’s a corresponding query: ```graphql query { repository(owner: "prismagraphql", name: "graphql-yoga") { name description # ask for more data here } } ``` However, what we *actually* want for our app (to avoid having to make multiple requests) is a root field looking as follows: ```graphql type Query { prismagraphqlRepositories(names: [String!]): [Repository!]! } ``` ### Requirement 3: Retrieve short description about the app itself [#requirement-3-retrieve-short-description-about-the-app-itself] Our API should be able to return a sentence describing our app, such as `"This app provides information about the Prisma GitHub organization"`. This is of course a completely custom requirement we can’t fulfil based on the GitHub API — but rather it’s clear that we need to implement it ourselves, potentially with a simple `Query` root field like this: ```graphql type Query { info: String! } ``` ### Defining the application schema [#defining-the-application-schema] We’re now aware of the required capabilities of our API and the ideal `Query` type we need to define for the schema: ```graphql type Query { prismagraphql: Organization! prismagraphqlRepositories(names: [String!]): [Repository!]! info: String! } ``` Obviously, this schema definition in itself is incomplete: it misses the definitions for the [`Organization`](https://gist.github.com/gc-codesnippets/a54ab279f6ea181f13a01a232f1aa958#file-github-graphql-L3005) and the [`Repository`](https://gist.github.com/gc-codesnippets/a54ab279f6ea181f13a01a232f1aa958#file-github-graphql-L5340) types. One straightforward way of solving this problem is to just manually copy and paste the definitions from GitHub’s schema definition. This approach quickly becomes cumbersome, since these type definitions themselves depend on other types in the schema (for example, the `Repository` type has a field [`codeOfconduct`](https://gist.github.com/gc-codesnippets/a54ab279f6ea181f13a01a232f1aa958#file-github-graphql-L5357) of type [`CodeOfConduct`](https://gist.github.com/gc-codesnippets/a54ab279f6ea181f13a01a232f1aa958#file-github-graphql-L420)) which you then need to manually copy over as well. There is no limit to how deep this dependency chain goes into the schema and you might even end up copying the full schema definition by hand. Note that when manually copying over types, there are three ways this can be done: * The entire type is copied over, no additional fields are added * The entire type is copied over and additional fields are added (or existing ones are renamed) * Only a subset of the type’s fields are copied over The first approach of simply copying over the full type is the most straightforward. This can be automated using [`graphql-import`](https://github.com/graphcool/graphql-import), as explained in the next section. If additional fields are added to the type definition or existing ones are renamed, you need to make sure to implement corresponding resolvers as the underlying API of course cannot take care of resolving these new fields. Lastly, you might decide to only copy over a subset of the type’s fields. This can be desirable if you don’t want to expose all the fields of a type (the underlying schema might have a `password` field on the `User` type which you don’t want to be exposed in your application schema). ### Importing GraphQL type definitions [#importing-graphql-type-definitions] The package [`graphql-import`](https://github.com/graphcool/graphql-import) saves you from that manual work by letting you share type definitions across different `.graphql`-files. You can import types from another GraphQL schema definition like so: ```graphql # import Repository from "./github.graphql" # import Organization from "./github.graphql" type Query { info: String! graphcoolRepositories(names: [String!]): [Repository!]! graphcool: Organization! } ``` In your JavaScript code, you can now use the `importSchema` function and it will resolve the dependencies for you, ensuring your schema definition is complete. ### Implementing the API [#implementing-the-api] With the above schema definition, we’re only halfway there. What’s still missing is the schema’s *implementation* in the form of *resolver* functions. > If you’re feeling lost at this point, make sure to read [this article](https://www.prisma.io/blog/graphql-server-basics-the-schema-ac5e2950214e) which introduces the basic mechanics and inner workings of GraphQL schemas. Let’s think about how to implement these resolvers! A first version could look as follows: ```js const { importSchema } = require('graphql-import') // Import the application schema, including the // types it depends on from `schemas/github.graphql` const typeDefs = importSchema('schemas/app.graphql') // Implement resolver functions for our three custom // root fields on the `Query` type const resolvers = { Query: { info: (parent, args) => 'This app provides information about the Prisma GitHub organization', prismagraphqlRepositories: (parent, { names }, context, info) => { // ??? }, prismagraphql: (parent, args, context, info) => { // ??? }, }, } ``` The resolver for `info` is trivial, we can return a simple string describing our app. But how to deal with the ones for `prismagraphql` and `prismagraphqlRepositories` where we actually need to return information from the GitHub GraphQL API? The naive way of implementing this here would be to look at the `info` argument to retrieve the *selection set* of the incoming query — then construct another GraphQL query from scratch that has the same selection set and send it to the GitHub API. This can even be facilitated by creating a [*remote schema*](https://www.prisma.io/blog/how-do-graphql-remote-schemas-work-7118237c89d7) for the GitHub GraphQL API but overall is still quite a verbose and cumbersome process. This is exactly where *schema delegation* comes into play! We saw before that GitHub’s schema exposes two root fields that (somewhat) cater the needs for our requirements: repositoryOwner and repository. We can now leverage this to save the work of creating a completely new query and instead *forward* the incoming one. ### Delegating to other schemas [#delegating-to-other-schemas] So, rather than trying to construct a whole new query, we simply take the incoming query and *delegate* its execution to another schema. The API we’re going to use for that is called [`delegateToSchema`](https://github.com/apollographql/graphql-tools/blob/master/src/stitching/delegateToSchema.ts#L31) provided by [`graphql-tools`](https://www.apollographql.com/docs/graphql-tools/). `delegateToSchema` receives seven arguments (in the following order): 1. `schema`: An executable instance of [GraphQLSchema](http://graphql.org/graphql-js/type/#graphqlschema) (this is the\* target schema\* we want to delegate the execution to) 2. `fragmentReplacements`: An object containing inline fragments (this is for more advanced cases we’ll not discuss in this article) 3. `operation`: A string with either of three values ( "query" , "mutation" or "subscription") indicating to which root type we want to delegate 4. `fieldName`: The name of the root field we want to delegate to 5. `args`: The input arguments for the root field we’re delegating to 6. `context`: The context object that’s passed through the resolver chain of the target schema 7. `info`: An object containing information about the query to be delegated In order for us to use this approach, we first need an executable instance of GraphQLSchema that represents the GitHub GraphQL API. We can obtain it using [makeRemoteExecutableSchema](https://www.prisma.io/blog/how-do-graphql-remote-schemas-work-7118237c89d7) from graphql-tools. > Notice that GitHub’s GraphQL API requires authentication, so you’ll need an [authentication token](https://github.com/settings/tokens) to make this work. You can follow this [guide](https://developer.github.com/v4/guides/forming-calls/#authenticating-with-graphql) to obtain one. In order to create the remote schema for the GitHub API, we need two things: * its *schema definition* (in the form of a `GraphQLSchema` instance) * an [`HttpLink`](https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-http) that knows how to fetch data from it We can achieve this using the following code: ```js // Read GitHub's schema definition from local file const gitHubTypeDefs = fs.readFileSync('./schemas/github.graphql', { encoding: 'utf8' }) // Instantiate `GraphQLSchema` with schema definition const introspectionSchema = makeExecutableSchema({ typeDefs: gitHubTypeDefs }) // Create `HttpLink` based using person auth token const link = new GitHubLink(TOKEN) // Create remote executable schema based on schema definition and link const schema = makeRemoteExecutableSchema({ schema: introspectionSchema, link, }) ``` [`GitHubLink`](https://github.com/nikolasburk/github-schema-delegation/blob/master/src/GitHubLink.js) is just a simple wrapper on top of `HttpLink`, providing a bit of convenience around creating the required Link component. Awesome, we now have an executable version of the GitHub GraphQL API that we can delegate to in our resolvers! 🎉 Let’s start by implementing the `prismagraphql` resolver first: ```js const resolvers = { Query: { // ... other resolvers prismagraphql: (parent, args, context, info) => { return delegateToSchema(schema, {}, 'query', 'repositoryOwner', { login: 'prismagraphql' }, context, info) }, }, } ``` We’re passing the seven arguments expected by the `delegateToSchema` function. Overall there are no surprises: The `schema` is the remote executable schema for the GitHub GraphQL API. In there, we want to delegate execution of our own `prismagraphql` query, to the `repositoryOwner` query from GitHub’s API. Since that field expects a `login` argument, we provide it with `"prismagraphql"` as its value. Finally we’re simply passing on the `info` and `context` objects through the resolver chain. The resolver for `prismagraphqlRepositories` can be approached in a similar fashion, yet it’s a bit trickier. What makes it different from the previous implementation is that the types of our `prismagraphqlRepositories: [Repository!]!` and the original field `repository: Repository` from GitHub’s schema definition don’t match up as nicely as before. We now need to return an *array* of repos, instead of a single one. Therefore, we go ahead and use Promise.all to make sure we can delegate multiple queries at once and bundle their execution results into an array of promises: ```js const resolvers = { Query: { // ... other resolvers prismagraphqlRepositories: (parent, { names }, context, info) => { return Promise.all( names.map(name => { return delegateToSchema(schema, {}, 'query', 'repository', { owner: 'prismagraphql', name }, context, info) }), ) }, }, } ``` This is it! We have now implemented all three resolvers for our custom GraphQL API. While the first one (for `info`) is trivial and simply returns a custom string, `prismagraphql` and `prismagraphqlRepositories` are using *schema delegation* to forward execution of queries to the underlying GitHub API. > If you want to see a working example of this code, check out this [repository](https://github.com/nikolasburk/github-schema-delegation). ## Schema delegation with `graphql-tools` [#schema-delegation-with-graphql-tools] In the above example of building a custom GraphQL API on top of GitHub, we saw how [`delegateToSchema`](https://github.com/apollographql/graphql-tools/blob/master/src/stitching/delegateToSchema.ts) can save us from writing boilerplate code for query execution. Instead of constructing a new query from scratch and sending it over with fetch, [`graphql-request`](https://github.com/graphcool/graphql-request) or some other HTTP tool, we can use the API provided by `graphql-tools` to delegate the execution of the query to another (executable) instance of `GraphQLSchema`. Conveniently, this instance can be created as a [remote schema](https://www.prisma.io/blog/how-do-graphql-remote-schemas-work-7118237c89d7). At a high-level, `delegateToSchema` simply acts as a “proxy” for the [`execute`](http://graphql.org/graphql-js/execution/#execute) function from [GraphQL.js](http://graphql.org/graphql-js). This means that under the hood it will reassemble a GraphQL query (or mutation) based on the information passed as arguments. Once the query has been constructed, all it does is [invoke `execute` with the schema and the query](https://github.com/apollographql/graphql-tools/blob/master/src/stitching/delegateToSchema.ts#L84). Consequently, schema delegation doesn’t necessarily require the target schema to be a remote schema, it can also be done with local schemas. In that regard, schema delegation is a very flexible tool— you might even want to delegate inside the *same* schema. This is basically the approach taken in [`mergeSchemas`](https://www.apollographql.com/docs/graphql-tools/schema-stitching.html#mergeSchemas) from `graphql-tools`, where multiple schemas are first merged into a single one, then the resolvers are rewired. In essence, schema delegation is about being able to easily forward queries to an existing GraphQL API. ## Schema binding: An easy way to reuse GraphQL APIs [#schema-binding-an-easy-way-to-reuse-graphql-apis] Equipped with our newly acquired knowledge about schema delegation, we can introduce a new concept which is nothing but a thin convenience layer on top of schema delegation, called *schema binding*. ### Bindings for public GraphQL APIs [#bindings-for-public-graphql-apis] The core idea of a schema binding is to provide an easy way for making an existing GraphQL API reusable so that other developers can now pull into their projects via NPM. This allows for an entirely new approach of building GraphQL “gateways” where it’s extremely easy to combine the functionality of multiple GraphQL APIs. With a dedicated binding for the GitHub API, we can now simplify the example from above. Rather than creating the remote executable schema by hand, this part is now done by the [`graphql-binding-github`](https://github.com/graphcool/graphql-binding-github) package. Here’s what the full implementation looks like where all the initial setup code we previously needed to delegate to the GitHub API is removed: ```js const { GitHub } = require('graphql-binding-github') const { GraphQLServer } = require('graphql-yoga') const { importSchema } = require('graphql-import') const TOKEN = '__YOUR_GITHUB__TOKEN__' // https://developer.github.com/v4/guides/forming-calls/#authenticating-with-graphql const github = new GitHub(TOKEN) const typeDefs = importSchema('schemas/app.graphql') const resolvers = { Query: { info: (parent, args) => 'This app provides information about the Prisma GitHub organization', prismagraphqlRepositories: (parent, { names }, context, info) => { return Promise.all( names.map(name => { return github.delegate('query', 'repository', { owner: 'prismagraphql', name }, context, info) }), ) }, prismagraphql: (parent, args, context, info) => { return github.delegate('query', 'repositoryOwner', { login: 'prismagraphql' }, context, info) }, }, } const server = new GraphQLServer({ typeDefs, resolvers }) server.start(() => console.log('Server running on http://localhost:4000')) ``` Instead of creating the remote schema ourselves, we’re simply instantiating the [`GitHub`](https://github.com/graphcool/graphql-binding-github/blob/master/src/index.ts#L20) class imported from `graphql-binding-github` and use its `delegate` function. It will then use `delegateToSchema` under the hood to actually perform the request. > Schema bindings for public GraphQL APIs can be shared among developers. Next to the [`graphql-binding-github`](https://www.google.de/search?q=graphql-github-binding\&oq=graphql-github-binding\&aqs=chrome..69i57.4859j0j1\&sourceid=chrome\&ie=UTF-8), there also already is a binding available for the Yelp GraphQL API: [`graphql-binding-yelp`](https://github.com/DevanB/graphql-binding-yelp) by [Devan Beitel](https://twitter.com/devanbeitel) ### Auto-generated delegate functions [#auto-generated-delegate-functions] The API for these sorts of schema bindings can even be improved to a level where delegate functions are *automatically generated*. Rather than writing the following `github.delegate('query', 'repository', ... )`, the binding could expose a function named after the corresponding root field: `github.query.repository( ... )`. When these delegate functions are generated in a build-step and based on a strongly typed language (like TypeScript or Flow), this approach will even provide compile-time type safety for interacting with other GraphQL APIs! To get a glimpse of what this approach looks like, check out the [prisma-binding](https://github.com/prismagraphql/prisma-binding) repository which allows to easily generate schema bindings for Graphcool services, and uses the mentioned approach of automatically generating delegate functions. ## Summary [#summary] This is our second article of the series “Understanding GraphQL schema stitching”. In the [first article](https://www.prisma.io/blog/how-do-graphql-remote-schemas-work-7118237c89d7), we did some groundwork and learned about remote (executable) schemas which are the foundation for most schema stitching scenarios. In this article, we mainly discussed the concept of *schema delegation* by providing a comprehensive example based on the [GitHub GraphQL API](https://developer.github.com/v4/) (the code for the example is available [here](https://github.com/nikolasburk/github-schema-delegation)). Schema delegation is a mechanism to forward (*delegate*) the execution of a resolver function to another resolver in a different (or even the same) GraphQL schema. Its key benefit is that we don’t have to construct an entirely new query from scratch but instead can reuse and forward (parts of) the incoming query. When using schema delegation as the foundation, it is possible to create dedicated NPM packages to easily share reusable *schema bindings* for existing GraphQL APIs. To get a sense of what these look like, you can check out the [bindings for the GitHub API](https://github.com/graphcool/graphql-binding-github) as well as the [prisma-binding](https://github.com/prismagraphql/prisma-binding) which allows to easily generate bindings for any Graphcool service.