Graphql-js: Compute field based on another field that return a promise

Created on 4 Feb 2016  路  1Comment  路  Source: graphql/graphql-js

Let's assume I have the type below

const myType = new GraphQLObject({
  name: "MyType",
  fields: {
     foo: {
        type: GraphQLBoolean,
        resolve: (_) => serviceCall()
     },
    bar: {
       type: GraphQLString,
       resolve: (obj) => obj.foo ? "bar1" : "bar2"
     }
  } 
})

foo is a boolean field and serviceCall return a promise. I want to be able to compute bar based on the value of foo. My problem is that obj.foo is always undefined.
I would like to be able to do something like:

resolve: (obj) => {
   return obj.foo.then((value) => value ? "bar1" : "bar2")
}
question

Most helpful comment

So obj in the second resolve function isn't an object on which we can access GraphQL fields on; it's the object returned by whatever field got us to this object. It looks like you're not using that object in the foo resolve function, so you probably don't need to do it here; instead, what you could do is:

const myType = new GraphQLObject({
  name: "MyType",
  fields: {
     foo: {
        type: GraphQLBoolean,
        resolve: (_) => serviceCall()
     },
    bar: {
       type: GraphQLString,
       resolve: (_) => serviceCall().then((value) => value ? "bar1" : "bar2")
     }
  } 
})

If the concern is calling serviceCall() twice, you could create a wrapper around it to ensure that it creates the same promise; in fact, this is behavior that might make sense to put on a JS business object representing MyType, so this would look like:

const myType = new GraphQLObject({
  name: "MyType",
  fields: {
     foo: {
        type: GraphQLBoolean,
        resolve: (obj) => obj.fooPromise()
     },
    bar: {
       type: GraphQLString,
       resolve: (obj) => obj.fooPromise().then((value) => value ? "bar1" : "bar2")
     }
  } 
})

Where fooPromise on the object calls serviceCall(), ensuring the resulting promise is memoized so it only gets called once.

Hope this helps!

>All comments

So obj in the second resolve function isn't an object on which we can access GraphQL fields on; it's the object returned by whatever field got us to this object. It looks like you're not using that object in the foo resolve function, so you probably don't need to do it here; instead, what you could do is:

const myType = new GraphQLObject({
  name: "MyType",
  fields: {
     foo: {
        type: GraphQLBoolean,
        resolve: (_) => serviceCall()
     },
    bar: {
       type: GraphQLString,
       resolve: (_) => serviceCall().then((value) => value ? "bar1" : "bar2")
     }
  } 
})

If the concern is calling serviceCall() twice, you could create a wrapper around it to ensure that it creates the same promise; in fact, this is behavior that might make sense to put on a JS business object representing MyType, so this would look like:

const myType = new GraphQLObject({
  name: "MyType",
  fields: {
     foo: {
        type: GraphQLBoolean,
        resolve: (obj) => obj.fooPromise()
     },
    bar: {
       type: GraphQLString,
       resolve: (obj) => obj.fooPromise().then((value) => value ? "bar1" : "bar2")
     }
  } 
})

Where fooPromise on the object calls serviceCall(), ensuring the resulting promise is memoized so it only gets called once.

Hope this helps!

Was this page helpful?
0 / 5 - 0 ratings