---
description:
  Learn how to combine multiple sources in GraphQL Mesh. Add new sources and shape the unified
  schema to leverage introspection to get its schema with just the endpoint URL.
---

import { Callout } from '@theguild/components'

# How to: Combine multiple Sources

All the documentation tutorials and guides rely on the "Books", "Authors" and "Stores" example APIs,
available in a dedicated repository:
[`graphql-mesh-docs-first-gateway`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway):

- Books API (REST API)
  - `GET /books`
  - `GET /books/:id`
  - `GET /categories`
- Authors API (gRPC API)
  - `GetAuthor`
  - `ListAuthors`
- Stores (GraphQL API)
  - `stores` Query
  - `bookSells(storeId: ID!)` Query

The getting started
["Your first Gateway with Mesh"](../../docs/getting-started/your-first-mesh-gateway) introduced the
configuration of the Books API Source.

This guide will show how to add 2 new sources (Authors and Stores) to achieve the following Gateway
setup:

```mermaid
graph TD;
subgraph AA [" "]
A[Mobile app];
B[Web app];
C[Node.js client];
end
subgraph BB [" "]
E[Books REST API];
F[Authors gRPC API];
G[Stores GraphQL API];
end
Z[Mesh Gateway GraphQL API];
A --> Z;
B --> Z;
C --> Z;
Z --> E;
Z --> F;
Z --> G;
```

We will go further than just add new Sources by shaping the Unified Schema to accept the following
query:

```graphql
query bestSellersByStore {
  stores {
    id
    name
    bookSells {
      sellsCount
      book {
        id
        title
        author {
          id
          name
        }
      }
    }
  }
}
```

## 1. Add the "Authors" Source

The "Authors" Source is a gRPC API:
[`authors-service`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/authors-service).

We will use the `grpc` Handler with the `@graphql-mesh/grpc` package and configure in our
[`.meshrc.yaml`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/multiple-sources/.meshrc.yaml)
it as follows:

```yaml filename=".meshrc.yaml"
sources:
  - name: Books
    handler:
      openapi:
        source: http://localhost:3002/openapi.json
  - name: Authors
    handler:
      grpc:
        endpoint: localhost:3003
```

Similar to the "Books" API configuration, we can either provide the path to the service definition
file (here, a Proto file) and the base URL or just the base URL if reflection is enabled. Our
"Authors" API supports reflection, so we can just provide the `endpoint` URL.

We will "clean" the corresponding "Authors" GraphQL Schema later, in the 3rd step, "_Shaping the
Unified Schema_".

## 2. Add the "Stores" Source

The "Stores" Source is a GraphQL API:
[`stores-service`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/stores-service).

We will use the `graphql` Handler with the `@graphql-mesh/graphql` package and configure it in our
[`.meshrc.yaml`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/multiple-sources/.meshrc.yaml)
it as follows:

```yaml filename=".meshrc.yaml"
sources:
  - name: Books
    handler:
      openapi:
        source: http://localhost:3002/openapi.json
  - name: Authors
    handler:
      grpc:
        endpoint: localhost:3003
  - name: Stores
    handler:
      graphql:
        endpoint: http://0.0.0.0:3004/graphql
```

Since the "Stores" is a GraphQL API, Mesh can leverage introspection to get its schema with just the
`endpoint` URL.

## 3. Shaping the Unified Schema

The following Mesh Gateway configuration
[`.meshrc.yaml`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/multiple-sources/.meshrc.yaml):

```yaml filename=".meshrc.yaml"
sources:
  - name: Books
    handler:
      openapi:
        source: http://localhost:3002/openapi.json
  - name: Authors
    handler:
      grpc:
        endpoint: localhost:3003
  - name: Stores
    handler:
      graphql:
        endpoint: http://0.0.0.0:3004/graphql
```

Will gives us a "raw" GraphQL schema design that contains unwanted GraphQL Queries, badly named
types, and a lack of hierarchy:

[`.mesh/schema.graphql`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/multiple-sources/.mesh/schema.graphql)

```graphql
type Query {
  AppController_books: [Book]
  AppController_categories: [Category]
  AppController_book(id: String!): Book
  stores: [Store!]!
  bookSells(storeId: ID!): [Sells!]!
  authors_v1_AuthorsService_GetAuthor(input: authors_v1_GetAuthorRequest_Input): authors_v1_Author
  authors_v1_AuthorsService_ListAuthors(
    input: authors_v1_ListAuthorsRequest_Input
  ): authors_v1_ListAuthorsResponse
  authors_v1_AuthorsService_connectivityState(tryToConnect: Boolean): ConnectivityState
}

# …
```

In order to achieve a clean Unified Schema design that would allow the following Query:

```graphql
query bestSellersByStore {
  stores {
    id
    name
    bookSells {
      sellsCount
      book {
        id
        title
        author {
          id
          name
        }
      }
    }
  }
}
```

We will need to configure multiple transforms:

- Rename the "Books" queries
- Rename the "Authors" queries
- Remove the unnecessary root queries: `author`, `book`, `categories`, `bookSells`
- Setup some hierarchy between the queries

**If you have never configured Transforms before**, we advise you to go through the
["Your first Gateway with Mesh"](/docs/getting-started/your-first-mesh-gateway) tutorial first.

### Remove unnecessary Root queries

Also covered in the ["Your first Gateway with Mesh"](/docs/getting-started/your-first-mesh-gateway)
tutorial, removing queries from the Unified Schema is achieved with the
`@graphql-mesh/transform-filter-schema` transform.

To build a clean Unified Schema, we need to remove unnecessary Queries such as:

- `Query.authors_v1_AuthorsService_GetAuthor` and `Query.authors_v1_AuthorsService_ListAuthors` from
  the "Authors" Source
- the `Query.!authors_v1_AuthorsService_connectivityState` is automatically generated by the `grpc`
  handler of the "Authors" Source
- `Query.AppController_book` and `Query.AppController_categories` from the "Books" Source
- `Query.bookSells` from the "Stores" Source

Our updated
[`.meshrc.yaml`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/multiple-sources/.meshrc.yaml)
is the following:

```yaml filename=".meshrc.yaml"
sources:
  - name: Books
    handler:
      openapi:
        source: http://localhost:3002/openapi.json
  - name: Authors
    handler:
      grpc:
        endpoint: localhost:3003
  - name: Stores
    handler:
      graphql:
        endpoint: http://0.0.0.0:3004/graphql
transforms:
  - filterSchema:
      filters:
        - Query.!bookSells
        - Query.!{AppController_book, AppController_categories}
        - Query.!authors_v1_AuthorsService_{connectivityState, GetAuthor}
```

`filterSchema` takes a `filters` option that accepts an array of filter rules.

By adding `Query.!bookSells`, we instruct Mesh to remove the `bookSells(...)` Query.

You can notice that the `filterSchema` allows using a bash-like syntax to avoid repetitive
configuration with the `{..., ...}` syntax.

Another way to achieve the same result would be to instruct Mesh only to keep the `Query.stores`
root query as follows:

```yaml filename=".meshrc.yaml"
sources:
  # ...
transforms:
  - filterSchema:
      filters:
        - Query.stores
```

More information on the `filterSchema` _Transform_ on
[its dedicated documentation page](/docs/transforms/filter-schema).

### Setup hierarchy with nested queries

To support the following Query:

```graphql
query bestSellersByStore {
  stores {
    id
    name
    bookSells {
      sellsCount
      book {
        id
        title
        author {
          id
          name
        }
      }
    }
  }
}
```

We need to update the schema to add the following fields:

- `Store.bookSells: [Sells!]!`: to get the selling from a given store
- `Sells.book: Book`: to get the book of a given store selling record
- `Book.author: authors_v1_Author`: to get the author of a book

To achieve this, we will use the `additionalResolvers` and `additionalTypeDefs` configuration from
Mesh's `.meshrc.yaml` API.

#### Add new field to the Schema

Using `additionalTypeDefs` configuration parameter allows writing GraphQL that will be merged with
the Unified Schema definition, allowing us to
[extend existing types](https://spec.graphql.org/June2018/#sec-Object-Extensions) and queries.

Let's say we want to add the `Book.author` field. We first need to know what is the type of Author.

Since the handlers generate most types, it might be hard to guess their correct spelling (e.g.
`authors_v1_Author`). A quick way to build an `additionalTypeDefs` is to refer to the generated
GraphQL Schema file of each Source that can be found in the
[`.mesh/sources`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/multiple-sources/.mesh/sources/)
folder.

For example, the GraphQL Schema of the "Authors" Source can be found at
[`.mesh/sources/Authors/schema.graphql`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/multiple-sources/.mesh/sources/Authors/schema.graphql)
file:

```graphql filename="schema.graphql"
schema {
  query: Query
}

type Query {
  authors_v1_AuthorsService_GetAuthor(input: authors_v1_GetAuthorRequest_Input): authors_v1_Author
  authors_v1_AuthorsService_ListAuthors(
    input: authors_v1_ListAuthorsRequest_Input
  ): authors_v1_ListAuthorsResponse
  authors_v1_AuthorsService_connectivityState(tryToConnect: Boolean): ConnectivityState
}

type authors_v1_Author {
  id: String
  name: String
  editor: String
}

input authors_v1_GetAuthorRequest_Input {
  id: String
}

type authors_v1_ListAuthorsResponse {
  items: [authors_v1_Author]
}

scalar authors_v1_ListAuthorsRequest_Input
  @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")

enum ConnectivityState {
  IDLE
  CONNECTING
  READY
  TRANSIENT_FAILURE
  SHUTDOWN
}
```

<Callout>Note: Try running the Mesh Gateway first if the `.mesh` folder does not exist.</Callout>

Here we find that an author is described with the `authors_v1_Author` GraphQL type, which allows us
to add the following `additionalTypeDefs` configuration
[`.meshrc.yaml`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/multiple-sources/.meshrc.yaml):

```yaml filename=".meshrc.yaml"
sources:
  # ...
transforms:
  - filterSchema:
      filters:
        - Query.stores
additionalTypeDefs: |
  extend type Book {
    author: authors_v1_Author
  }
```

By applying the same process for `Store.bookSells` and `Sells.book`, we get the following final
`additionalTypeDefs` configuration
[`.meshrc.yaml`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/multiple-sources/.meshrc.yaml):

```yaml filename=".meshrc.yaml"
sources:
  # ...
transforms:
  - filterSchema:
      filters:
        - Query.stores
additionalTypeDefs: |
  extend type Store {
    bookSells: [Sells!]!
  }
  extend type Sells {
    book: Book
  }
  extend type Book {
    author: authors_v1_Author
  }
```

Our Unified Schema definition is now updated; we need to point to Mesh on how to resolve our new
field's data.

#### Add resolvers for the new fields

Now, let's describe **how Mesh should resolve the data on the newly added type definitions** by
using the `@resolveTo` directive.

Again, let's start with the `Book.author` field.

We need the `Book.author` field to call the
`Query.authors_v1_AuthorsService_GetAuthor(input: authors_v1_GetAuthorRequest_Input): authors_v1_Author`
Query by providing the following `@resolveTo` directive:
[`.meshrc.yaml`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/multiple-sources/.meshrc.yaml):

```yaml filename=".meshrc.yaml" {11-21}
sources:
  # ...
additionalTypeDefs: |
  extend type Store {
    bookSells: [Sells!]!
  }
  extend type Sells {
    book: Book
  }
  extend type Book {
    author: authors_v1_Author @resolveTo(
      sourceName: "Authors"                                   # Which source does the target field belong to?
      sourceTypeName: "Query",                                # Which root type does the target field belong to?
      sourceFieldName: "authors_v1_AuthorsService_GetAuthor", # What is the source field name?
      requiredSelectionSet: "{ authorId }",                   # What is the required selection on the target type to resolve the source field?
      sourceArgs: {                                           # What args the source field does need?
        input: {
          id: "{root.authorId}"
        }
      }
    )
  }
```

Here, the `@resolveTo` directive explains that Querying `Book.author` will resolve the data by
calling the `Query.authors_v1_AuthorsService_GetAuthor` from the "Authors" source.

The `requiredSelectionSet` and `sourceArgs` ensure that the required arguments are provided
(`requiredSelectionSet`) and adequately mapped to the Source (`sourceArgs`). `requiredSelectionSet`
ensures that the `Book.author` selection will contains `authorId`, so it can be forward to
`Query.authors_v1_AuthorsService_GetAuthor` as the `input.id` argument.

Applying the same logic to `Stores.bookSells` and `Sells.book` gives us a complete
[`.meshrc.yaml`](https://github.com/charlypoly/graphql-mesh-docs-first-gateway/tree/master/packages/multiple-sources/.meshrc.yaml)
configuration.

#### Run the Mesh Gateway

Our Gateway is now complete; you can start it (along with the Services APIs) by running:

```sh
yarn start-multiple-sources
```

Then, the following query is now properly resolving all the fields:

```graphql
query bestSellersByStore {
  stores {
    id
    name
    bookSells {
      sellsCount
      book {
        id
        title
        author {
          id
          name
        }
      }
    }
  }
}
```

Which returns the correct data:

![GraphQL Unified Schema with GraphiQL](/assets/docs/how-tos/combine-multiple-sources/mesh-final-graphiql.png)

Congrats! 🎉

You are now familiar with the basics of GraphQL Mesh:

- Configuring _Sources_, _Handlers_, _Transforms_
- and shaping the _Unified Schema_ with `additionalTypeDefs` and `additionalResolvers`.

## Going further

We provide a set of guides that will help you get started on more realistic scenarios, such as:

- Handling Sources with no definition
- Customize the Mesh server (caching, Envelop plugins)
- Deploying a GraphQL Mesh gateway

As well as some advanced guides for more complex schemas:

- Order of transforms, Sources' Schema, and unified Schema
- Extending the Unified Schema (`additionalResolvers` guide)
- Error handling
- File upload
- Subscriptions & Live Queries
