graphql-weaver icon indicating copy to clipboard operation
graphql-weaver copied to clipboard

Access to rootValue

Open moret opened this issue 7 years ago • 2 comments

Hi! I've tried weaving two schemas, one of which was queried before using graphql-js' rootValue argument. The resulting schema however does not seem to be getting the rootValue that is set.

Steps to reproduce: Run one of the following examples:

const {
  graphql,
  GraphQLObjectType,
  GraphQLSchema,
  GraphQLString,
} = require('graphql');
const { weaveSchemas } = require('graphql-weaver');

const beverageSchema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'beverage',
    fields: {
      beverage: {
        resolve: (root, args, ctx, ast) => {
          if (
            (root && root.bar) ||
            (ast && ast.rootValue && ast.rootValue.bar)
          ) {
            return '🍺';
          }
          return '💧';
        },
        type: GraphQLString
      }
    },
  })
});

const foodSchema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'food',
    fields: {
      food: {
        resolve: () => '🍔',
        type: GraphQLString
      }
    },
  })
});

// http://graphql.org/graphql-js/graphql/#graphql
graphql(
  beverageSchema,
  '{ beverage }'
).then(result => {
  console.assert(
    result.data.beverage == '💧',
    'beverage schema without root did not return 💧'
  );
}).catch(e => {
  console.log(e);
});
graphql(
  beverageSchema,
  '{ beverage }',
  { bar: true }
).then(result => {
  console.assert(
    result.data.beverage == '🍺',
    'beverage schema with root did not return 🍺'
  );
}).catch(e => {
  console.log(e);
});
graphql(
  foodSchema,
  '{ food }'
).then(result => {
  console.assert(
    result.data.food == '🍔',
    'food schema did not return the 🍔'
  );
}).catch(e => {
  console.log(e);
});

weaveSchemas({endpoints: [
  { schema: beverageSchema },
  { schema: foodSchema },
]}).then(theGrandSchema => {
  graphql(
    theGrandSchema,
    '{ beverage }'
  ).then(result => {
    console.assert(
      result.data.beverage == '💧',
      'the grand schema without root did not return 💧'
    );
  });
  graphql(
    theGrandSchema,
    '{ beverage }',
    { bar: true }
  ).then(result => {
    console.assert(
      result.data.beverage == '🍺',
      'the grand schema with root did not return 🍺'
    );
  }).catch(e => {
    console.log(e);
  });
  graphql(
    theGrandSchema,
    '{ food }'
  ).then(result => {
    console.assert(
      result.data.food == '🍔',
      'the grand schema did not return the 🍔'
    );
  }).catch(e => {
    console.log(e);
  });
});

Expected behaviour: Queries on the beverage root with a { bar: true } set as root should return "🍺 ".

Actual behaviour Queries on the beverage root with a { bar: true } set return "💧 ".

moret avatar Oct 25 '17 16:10 moret

Thanks for your feedback. You're correct, the rootValue is currently not propagated. It makes sense to propagate the rootValue to endpoints without namespace declaration, like in your example. Does your use case also include endpoints with namespaces? I think it would still be a good idea to set the rootValue in the GraphQLResolveContext, but what about source? Should it be set to the rootValue`? Should we just try to access a field on the rootValue with the same name as the namespace on the endpoint?

Yogu avatar Oct 25 '17 18:10 Yogu

hmm... in my particular case only the "old" schema, which has no namespace declaration, would use a rootValue, the other weaved schemas with namespaces are from upstream services, so the rootValue is not really useful to them. But I can imagine that other people might try to weave local schemas that implement patterns such as the one DataLoader per request with namespaces. Using fields with the same name on the rootValue sounds good.

moret avatar Oct 25 '17 19:10 moret