You can execute GraphQL queries against remote schemas by using a gateway that aggregates multiple GraphQL services.

Let’s see it in action. Imagine you have two separate GraphQL services: one for users and one for products.

User Service (users.graphql):

type User {
  id: ID!
  name: String!
  email: String
}

type Query {
  user(id: ID!): User
  users: [User!]!
}

Product Service (products.graphql):

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

type Query {
  product(id: ID!): Product
  products: [Product!]!
}

Now, you want to query for a user’s name and the products they are selling. Without a gateway, you’d have to make two separate requests to two different GraphQL endpoints.

With a gateway, you can define a unified schema that pulls in types from both services.

Gateway Schema (gateway.graphql):

# Pulls in the User type from the User Service
extend type Query {
  user(id: ID!): User
}

# Pulls in the Product type from the Product Service
extend type Query {
  product(id: ID!): Product
}

# Define a new type that combines User and Product information
type UserProducts {
  user: User!
  products: [Product!]!
}

# Add a new query to the gateway schema
extend type Query {
  userProducts(userId: ID!): UserProducts
}

The gateway will then have resolvers that know how to fetch data from the underlying services. For instance, the userProducts resolver would first query the User Service for the user’s details and then query the Product Service for products where sellerId matches the fetched user’s id.

Here’s what a client request to the gateway might look like:

query GetUserAndTheirProducts($userId: ID!) {
  userProducts(userId: $userId) {
    user {
      id
      name
      email
    }
    products {
      id
      name
      price
    }
  }
}

The gateway receives this query. It breaks it down. It knows that user and email (via userProducts.user) need to go to the User Service. It knows that id, name, and price (via userProducts.products) need to go to the Product Service. It executes these sub-queries concurrently (or in an optimized order) and then stitches the results back together into the single UserProducts response.

The core problem this solves is schema federation or schema stitching. Instead of a single, monolithic GraphQL API that becomes difficult to manage as it grows, you can break it down into smaller, independent GraphQL services. Each service owns a specific domain (like users, products, orders). The gateway then acts as a single entry point, presenting a unified view of all these services to the client. This allows teams to work on their respective services independently, deploy them separately, and evolve their schemas without impacting other teams.

The mental model is that of a smart proxy. The gateway understands the unified schema and how it maps to the underlying schemas of the individual services. When a query comes in, it inspects the query, determines which underlying services own which fields, and orchestrates the fetching of data. It’s not just blindly forwarding requests; it’s intelligently decomposing and recomposing them.

A surprising aspect is how easily you can introduce new fields or even entirely new services into your GraphQL API without clients needing to change their existing queries, as long as those new additions are part of the unified schema exposed by the gateway. The gateway’s schema can evolve independently of the underlying services’ schemas to a certain extent, allowing for backward compatibility and graceful deprecation.

The actual implementation of the gateway often involves libraries like Apollo Federation or custom solutions built with GraphQL server frameworks. These libraries provide the tools to define how your gateway schema extends and composes the schemas from your individual services. You’ll typically configure your gateway with the URLs of your downstream services and a way to fetch their schemas.

The next concept you’ll likely encounter is how to handle complex relationships and mutations across these federated services.

Want structured learning?

Take the full Graphql-tools course →