Docs
Guides
Extending the Unified Schema

Extending the Unified Schema

We saw on the “How to: Combine multiple Sources” guide that additionalResolvers could be used to shape and augment the Unified Schema with custom resolvers.

However, the additionalResolvers value can also be the path to a JavaScript/TypeScript file that exports the custom resolvers implementation.

Programmatic additionalResolvers

In our “How to: Combine multiple Sources” Gateway, the additionalResolvers could have been provided programmatically as shown in the multiple-sources-prog-resolvers example.

The below .meshrc.yaml configuration 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

.meshrc.yaml

.meshrc.yaml
sources:
  # …
transforms:
  # …
additionalTypeDefs: |
  extend type Store {
    bookSells: [Sells!]!
  }
  extend type Sells {
    book: Book
  }
  extend type Book {
    author: authors_v1_Author
  }
 
additionalResolvers:
  - './resolvers'

resolvers.ts

resolvers.ts
import { Resolvers } from './.mesh'
 
const resolvers: Resolvers = {
  Book: {
    author: {
      selectionSet: /* GraphQL */ `
        {
          authorId
        }
      `,
      resolve(root, _args, context, info) {
        return context.Authors.Query.authors_v1_AuthorsService_GetAuthor({
          root,
          args: {
            input: {
              id: root.authorId
            }
          },
          context,
          info
        })
      }
    }
  },
  Store: {
    bookSells: {
      selectionSet: /* GraphQL */ `
        {
          id
        }
      `,
      resolve(root, _args, context, info) {
        return context.Stores.Query.bookSells({
          root,
          args: {
            storeId: root.id
          },
          context,
          info
        })
      }
    }
  },
  Sells: {
    book: {
      selectionSet: /* GraphQL */ `
        {
          bookId
        }
      `,
      resolve(root, _args, context, info) {
        return context.Books.Query.book({
          root,
          args: {
            id: root.bookId
          },
          context,
          info
        })
      }
    }
  }
}
 
export default resolvers

Mesh relies on GraphQL Code Generator to generate the Resolvers type that gives you access to:

  • fully typed resolvers map
  • fully typed SDK (through the context) to fetch data from Sources

Using the SDK to fetch Sources

Let’s take a closer look at the Book.author resolver implementation.

The resolver is accessing the “Authors” source SDK through the context to fetch data from the authors_v1_AuthorsService_GetAuthor(id: ID!) Query as follows:

await context.Authors.Query.authors_v1_AuthorsService_GetAuthor({
  root,
  args: {
    input: {
      id: root.authorId
    }
  },
  context,
  info
})

authors_v1_AuthorsService_GetAuthor is a generated SDK method that allows to query our gRPC Books Source as it was a GraphQL Schema.

Any SDK method take the following arguments:

  • root, context and info are mandatory parameters that we forward from the resolvers calling the method. If the current field’s return type doesn’t match, you should provide a selectionSet.
  • args: arguments to pass to the Mutation or Query
  • selectionSet: allows to specify a selection on the Query/Mutation to fetch nested data like { id name }
  • valuesFromResults: allows to provide a function to transform the results (if the result is an array, the function will be mapped to each element)
💡

Note: valuesFromResults, compared to selectionSet helps to “flatten”/“un-nest” data from results

Going further

Transforms like “Hoist Field” also helps in shaping and extending the Unified Schema.