简体   繁体   中英

GraphQL unable to resolve nested object property

I am trying to return a graphQL query with some nested property objects in a list. Everything seems to check out, but am getting null values.

Expected datastructure response (more detail on structure here ):

//Return a GraphQLList type of all objects :    
[
    {
        "subscription" : {

        },
        "customer" : {

        },
    },
]

the query: { subscriptions { subscription { id customer_id } } }

GraphQL Query Object:

var Query = new graphQL.GraphQLObjectType({
    name: 'Query',
    description: 'Root of the Schema',
    fields: {
        subscriptions: {
            type: new graphQL.GraphQLList(SubscriptionsList),
            args : {
                customer_name: { type: graphQL.GraphQLString },
                customer_id: { type: graphQL.GraphQLString }
            },
            resolve : function (source, args) {
                return getSubscriptions().then(function (res) {
                    // Shows that data is returned
                    console.log('Data: ', res.list);

                    return res.list;
                }).catch(function (err) {
                    return err;
                });
            }
        }
    }
});

Which expects to return type GraphQLList of SubscriptionsList :

var SubscriptionsList = new graphQL.GraphQLObjectType({
    name : 'SubscriptionObj',
    description : 'stuff',
    fields : function () {
        return {
            subscription : {
                type : Subscription,
                resolve : function (subscription) {
                    return  subscription;
                }
            }
        }
    }
});

Which should resolve the nested field property:

var Subscription = new graphQL.GraphQLObjectType({
    name : 'Subscription',
    description : 'stuff',
    fields : function () {
        return {
            id: {type: graphQL.GraphQLString},
            customer_id: {type: graphQL.GraphQLString}
        }
    }
});

Console.log(res.list) Output (from Query): I am definitely getting the data and structure I expect:

[ { subscription: 
     { id: 'cbdemo_lloyd-sub2',
       customer_id: 'cbdemo_lloyd',
       plan_id: 'cbdemo_nuts',
       addons: [Object],
       due_invoices_count: 0,
       shipping_address: [Object] },
    customer: {
       ...
    }
  },
  {...}
]

GraphQL Query Output:

{
  "data": {
    "subscriptions": [
      {
        "subscription": {
          "id": null,
          "customer_id": null
        }
      },
      {
        "subscription": {
          "id": null,
          "customer_id": null
        }
      },

EDIT Not really necessary, but here is the getSubscriptions() API call that returns a promise:

function getSubscriptions() {
    return new Promise(function (resolve, reject) {
        chargebee.subscription.list({
            limit : 5,
            "plan_id[is_not]" : "basic",
            "status[is]" : "active",
            "sort_by[asc]" : "created_at"
        }).request(function(error,result){
            if (error) return reject(error);
            return resolve(result);
        });
    });
}

Looks like you are getting abit confused, Basiclly, when you set

new graphQL.GraphQLList(SubscriptionsList),

this is already a list. which means what you really meant is

new graphQL.GraphQLList(Subscription),

Next, your subscription object does not contain any resolve logic, so i would expect it to be something like this:

var Subscription = new graphQL.GraphQLObjectType({
    name : 'Subscription',
    description : 'stuff',
    fields : function () {
        return {
            id: {
                   type: graphQL.GraphQLString,
                   resolve: function(subscription) {
                       return subscription.subscription.id;
                   }
            },
            customer_id: {
                   type: graphQL.GraphQLString,
                   resolve: function(subscription) {
                       return subscription.subscription.customer_id;
                   }
            },
        }
    }
});

What basically happens under the hood, is that GraphQL will resolve each javascript object in the list provided, using the Subscription object. each resolver there will get the javascript object as the first value, and return the basic value from it.

I think the resolver in your SubscriptionsList has to return subscription.subscription . I would consider changing the name of subscriptionsList, because it's quite confusing.

The way I see it, you should just have a GraphQLList(Subscription) and remove that extra level of nesting. Either that, or call the thing that contains a subscription and a customer something else.

According to your post, res.list shows the following:

// listing #1
[
  { 
    subscription: {
      id: 'cbdemo_lloyd-sub2',
      customer_id: 'cbdemo_lloyd',
      plan_id: 'cbdemo_nuts',
      addons: [Object],
      due_invoices_count: 0,
      shipping_address: [Object] },
      customer: {
        ...
      }
  },
  {...}
]

Now, the above result corresponds to subscriptions field in your Query , which is a list of SubscriptionsList . Therefore, value of a SubscriptionsList will be item from the above listing #1:

// listing #2
{
  subscription: {
    id: 'cbdemo_lloyd-sub2',
    customer_id: 'cbdemo_lloyd',
    plan_id: 'cbdemo_nuts',
    addons: [Object],
    due_invoices_count: 0,
    shipping_address: [Object] },
    customer: {
      ...
    }
  }
}

In SubscriptionsList type, you have a field subscription . Its resolve function returns whatever it gets. So the field subscription remains the same as listing #2.

While resolving subscription field (type Subscription ), it looks for id and customer_id properties in object shown in listing #2. But that object has only subscription property. Therefore, id and customer_id fields receive null values.

Thus, the problem is in the resolve function of subscription field. Its input is object in listing #2 and its output should be the object in the following listing #3:

// listing #3
{
  id: 'cbdemo_lloyd-sub2',
  customer_id: 'cbdemo_lloyd',
  plan_id: 'cbdemo_nuts',
  addons: [Object],
  due_invoices_count: 0,
  shipping_address: [Object] },
  customer: {
    ...
  }
}

To get the object in listing #3, change in your SubscriptionsList type:

subscription : {
    type : Subscription,
    resolve : function (item) { // item is listing #2
        return  item.subscription; // item.subscription is listing #3
    }
}

On a different note, the GraphQL object type SubscriptionsList is actually unnecessary here and made the whole thing complicated. The whole design will become a lot simpler without it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM