0
votes

I'm trying to make my GraphQL schema composable through schema stitching, but I'm struggling with how to resolve properties of types from a different part.

Here's the schema before decomposing:

type Referee {
  id: ID!
  stringProp: String!
}

type Referer {
  id: ID!
  pointer: Referee!
}

type Query {
  referers: [Referer]
}

The types both have resolvers, in their respective schemas, that expand object { id } into { id, stringProp } or { id, pointer: { id } }, so that a query

query FromSingleSchema {
  referers: {
    id
    pointer {
      id
      stringProp
    }
  }
}

resolves as expected; Query.referers resolves to a list of [{id}] objects, and each of those in turn resolve first into a Referer and then fetches the pointed-to Referee through type resolvers.

Now, I try to decompose the schema:

// schema A
type Referee {
  id: ID!
  stringProp: String!
}

// schema B
type Referer {
  id: ID!
}

type Query {
  referers: [Referer]
}

// schema Extensions
extend type Referer {
  pointer: Referee!
}

and compose it again:

// both schemaA and schemaB have been created with makeExecutableSchema
import schemaA from './A'
import schemaB from './B'
// schemaExtensions is just a raw GraphQL string
// resolverExtensions is shown below
import { schemaExtensions, resolverExtensions } from './B'

const schema = mergeSchemas({
  schemas: [schemaA, schemaB, schemaExtensions],
  resolvers: Object.assign({}, resolverExtensions)
})

// resolverExtensions defined as follows:
{
  Referer: {
    pointer: {
      fragment: 'fragment IdFragment on Referee { id }',
      resolve: o => ({ id: o.pointerId })
    }
  }
}

With this, I can run this query without problems:

query OnlyIdFromDecomposedSchemas {
  referers: {
    id
    pointer {
      id
    }
  }
}

but this fails

query FullRefereeFromDecomposedSchemas {
  referers: {
    id
    pointer {
      id
      stringProp
    }
  }
}

with the error message

Cannot return null for non-nullable field Referee.stringProp.

What do I need to do for the type resolver for Referee to be able to fill in the rest of the properties once { id } is available, like it does in a single, non-decomposed, schema?

1

1 Answers

1
votes

I think you are looking for schema delegation. Schema Delegation is a way to automatically forward a query (or a part of a query) from a parent schema to another schema (called a subschema) that is able to execute the query.

You can use delegateToSchema method like this in your resolver:

{
    Referer: {
      pointer : {
        resolve(parent, args, context, info) {
          return info.mergeInfo.delegateToSchema({
            schema: schemaA,
            operation: 'query',
            fieldName: 'referee', // modify according to your query for referee
            context,
            info,
          });
        }
      }
    }
  }