GraphQL Schema Stitching

Friday, March 17th 2023

Suppose you have two separate GraphQL APIs, each with its own schema: products and reviews. The products API has a Product type, and the reviews API has a Review type. You want to create a unified GraphQL API that includes both types, so that clients can query for products and their associated reviews in a single request.

To do this, you can use schema stitching. Here's an example:

  1. Define the schema for each API

First, you define the schema for each API. Here's an example for the products API:

type Product { id: ID! name: String! price: Float! }

And here's an example for the reviews API:

type Review { id: ID! productId: ID! rating: Int! comment: String! }
  1. Define resolvers for each API

Next, you define resolvers for each API. These resolvers will be used to fetch data from the underlying data sources. Here's an example for the products API:

const products = [ { id: '1', name: 'Product 1', price: 10.0 }, { id: '2', name: 'Product 2', price: 20.0 }, { id: '3', name: 'Product 3', price: 30.0 }, ]; const productResolver = { Query: { product: (_, { id }) => products.find(p => p.id === id), }, };

And here's an example for the reviews API:

const reviews = [ { id: '1', productId: '1', rating: 5, comment: 'Great product!' }, { id: '2', productId: '1', rating: 4, comment: 'Good product.' }, { id: '3', productId: '2', rating: 3, comment: 'Okay product.' }, { id: '4', productId: '3', rating: 2, comment: 'Not so great.' }, ]; const reviewResolver = { Query: { review: (_, { id }) => reviews.find(r => r.id === id), reviewsForProduct: (_, { productId }) => reviews.filter(r => r.productId === productId), }, };
  1. Stitch the schemas together

Now you can stitch the schemas together using the makeExecutableSchema function from the graphql-tools package. Here's an example:

const { makeExecutableSchema } = require('graphql-tools'); const productSchema = ` type Product { id: ID! name: String! price: Float! reviews: [Review] } type Query { product(id: ID!): Product } `; const reviewSchema = ` type Review { id: ID! productId: ID! rating: Int! comment: String! } type Query { review(id: ID!): Review reviewsForProduct(productId: ID!): [Review] } `; const schema = makeExecutableSchema({ typeDefs: [productSchema, reviewSchema], resolvers: [productResolver, reviewResolver], }); module.exports = schema;

The makeExecutableSchema function takes an array of type definitions and an array of resolver functions, and returns a single schema that includes both types. In this example, we're defining a new Product type that includes a list of Review objects.