Graphql-tools: Add a way to delegate to a non-root field

Created on 18 Dec 2017  路  9Comments  路  Source: ardatan/graphql-tools

ver : 2.2.1
some micro service has this queries :

    meetingQueries: {
           getMeetingsByDates(startDate, endDate): [Meeting]
           ......
    }

when I try to stitch him, in the resolver I can't use "getMeetingsByDate" because his not defined in the microservice root queries.

I get:

"Cannot find subschema for root field "query.getMeetingsByDates" ".

so I tried instead of :

mergeInfo.delegate(
`query`,
`getMettingsByDates`
.........)

to do :

mergeInfo.delegate(
`query`,
`meetingQueries.getMettingsByDates`
.........)

yet still I can't find a way to reach a subquery, and couldn't find any documentation on it.

feature schema stitching

Most helpful comment

You can totally do this already with Transforms. The documentation doesn't really make sense around it:

https://www.apollographql.com/docs/graphql-tools/schema-transforms.html#Modifying-types

But if you look at the tests, it may make a bit more sense:

https://github.com/apollographql/graphql-tools/blob/b85137ba81c9bdc5667bced9cad9b1d226ea83fc/src/test/testTransforms.ts

As far as your specific example, I haven't tried it yet, but it's something like this:

const { WrapQuery } = require('graphql-tools')
const { Kind } = require('graphql')

return info.mergeInfo.delegateToSchema({
  schema: authorSchenam
  operation: 'query',
  fieldName: 'meetingQueries',
  args: { id: nodeId },
  context,
  info,
  transforms: [
    new WrapQuery(
      [ 'meetingQueries' ],
      (subtree) => {
        return {
          selectionSet: {
            thing: Kind.SELECTION_SET,
            selections: [
              {
                kind: Kind.FIELD,
                name: {
                  kind: Kind.NAME,
                  value: 'getMeetingsByDates'
                },
                arguments: [
                  {
                    kind: Kind.ARGUMENT,
                    name: {
                      kind: Kind.NAME,
                      value: startDate
                    }
                    value: {
                      kind: Kind.VARIABLE,
                      name: {
                        kind: Kind.NAME,
                        value: startDate
                      }
                    }
                  },
                  {
                    kind: Kind.ARGUMENT,
                    name: {
                      kind: Kind.NAME,
                      value: endDate
                    }
                    value: {
                      kind: Kind.VARIABLE,
                      name: {
                        kind: Kind.NAME,
                        value: endDate
                      }
                    }
                  }
                ],
                selectionSet: subtree
              }
            ]
          }
        }
      }
    , 
    result => result && result.meetingQueries && result.meetingQueries.getMeetingsByDates)
  ]
})

All 9 comments

@stubailo did you ever find a solution to this question? I have the same need but can't find any documentation.

Having this same issue. Was anyone able to figure this out?

I have the same issue, I can be wrong, but if you know how resolve this field, you can resolve inside the merging resolver.

mergeSchemas({
    schemas,
    resolvers: mergeInfo => ({
      SomeField1: {
        someField2: {
          fragment: '...',
          resolve(parent, args, { db }, info) {
            return db.SomeField.findOne({ where: { id: parent.id } });
         }
    }
  }

Ah ok that makes sense. Thanks!

I'm facing this issue as well. Would be great to be able to pass a full query + fragment to the delegate method that allows us to query a nested field. Maybe something like this (based on the example https://www.apollographql.com/docs/graphql-tools/schema-stitching.html#basic-example):

Chirp_Chirp: {
  author: {
    fragment: `... on Chirp { authorId }`,
    resolve(chirp, args, context, info, chirpAuthorFragment) {
      return info.mergeInfo.delegateToSchema({
        schema: authorSchema,
        query: gql`
          query User($token: String, $authorId: String) {
            viewer(token: $token) {
              userById(id: $authorId) {
                ...ChirpAuthor
              }
            }
          }
          ${chirpAuthorFragment}
        `,
        variables: {
          token: context.token,
          authorId: chirp.authorId
        },
        context,
        info,
      });
    },
  },
},

You can totally do this already with Transforms. The documentation doesn't really make sense around it:

https://www.apollographql.com/docs/graphql-tools/schema-transforms.html#Modifying-types

But if you look at the tests, it may make a bit more sense:

https://github.com/apollographql/graphql-tools/blob/b85137ba81c9bdc5667bced9cad9b1d226ea83fc/src/test/testTransforms.ts

As far as your specific example, I haven't tried it yet, but it's something like this:

const { WrapQuery } = require('graphql-tools')
const { Kind } = require('graphql')

return info.mergeInfo.delegateToSchema({
  schema: authorSchenam
  operation: 'query',
  fieldName: 'meetingQueries',
  args: { id: nodeId },
  context,
  info,
  transforms: [
    new WrapQuery(
      [ 'meetingQueries' ],
      (subtree) => {
        return {
          selectionSet: {
            thing: Kind.SELECTION_SET,
            selections: [
              {
                kind: Kind.FIELD,
                name: {
                  kind: Kind.NAME,
                  value: 'getMeetingsByDates'
                },
                arguments: [
                  {
                    kind: Kind.ARGUMENT,
                    name: {
                      kind: Kind.NAME,
                      value: startDate
                    }
                    value: {
                      kind: Kind.VARIABLE,
                      name: {
                        kind: Kind.NAME,
                        value: startDate
                      }
                    }
                  },
                  {
                    kind: Kind.ARGUMENT,
                    name: {
                      kind: Kind.NAME,
                      value: endDate
                    }
                    value: {
                      kind: Kind.VARIABLE,
                      name: {
                        kind: Kind.NAME,
                        value: endDate
                      }
                    }
                  }
                ],
                selectionSet: subtree
              }
            ]
          }
        }
      }
    , 
    result => result && result.meetingQueries && result.meetingQueries.getMeetingsByDates)
  ]
})

@gviligvili any chance you'd repost this to stack overflow? It'd be great to get the rep for this. Apparently a bunch of people have been having this particular issue

@dncrews Thank you; this is a huge help.

For others reading, the return value of the (subtree) => { /* ... */ } function is a GraphQL AST node representing the query that's made to the sub-schema authorSchema. Equivalent to what I've highlighted here:

screen shot 2018-11-19 at 2 27 17 pm

https://astexplorer.net/#/gist/078337bd6ad24069f0c9183e22f286d2/d10f9974b78eb16dcdb02f7595469099db84d9ef

In the above example, the id and title fields are the selection set from the original query which we're passing along to the sub-query, i.e. the subtree value.


Here is a more complete example which is similar to what I'm doing in my application, using additional schema transforms too: https://gist.github.com/elliottsj/fa7042c0588ea6df1bc2f02f583d1100

New TransformQuery transform replaces WrapQuery and ExtractField and should do the job, folded into #1306 .

Was this page helpful?
0 / 5 - 0 ratings