Search code examples
aws-lambdaamazon-dynamodbgraphqlgraphql-jsaws-appsync

Graphql returning Cannot return null for non-nullable field Query.getDate. As I am new to graphql I want to know is my approach is wrong or my code?


I have created resolver, schema and handler which will fetch some record from dynamoDB. Now when I perform query then I am getting "Cannot return null for non-nullable field Query.getDate" error. I would like to know whether my approach is wrong or there is any change required in code.

My code : https://gist.github.com/vivek-chavan/95e7450ff73c8382a48fb5e6a5b96025

Input to lambda :

{
  "query": "query getDate {\r\n      getDate(id: \"0f92fa40-8036-11e8-b106-952d7c9eb822@eu-west-1:ba1c96e7-92ff-4d63-879a-93d5e397b18a\") {\r\n        id\r\n        transaction_date\r\n      }\r\n     }"
}

Response :

{
  "errors": [
    {
      "message": "Cannot return null for non-nullable field Query.getDate.",
      "locations": [
        {
          "line": 2,
          "column": 7
        }
      ],
      "path": [
        "getDate"
      ]
    }
  ],
  "data": null
}

Logs of lambda function :

[ { Error: Cannot return null for non-nullable field Query.getDate.
         at completeValue (/var/task/node_modules/graphql/execution/execute.js:568:13)
         at completeValueCatchingError (/var/task/node_modules/graphql/execution/execute.js:503:19)
         at resolveField (/var/task/node_modules/graphql/execution/execute.js:447:10)
         at executeFields (/var/task/node_modules/graphql/execution/execute.js:293:18)
         at executeOperation (/var/task/node_modules/graphql/execution/execute.js:237:122)
         at executeImpl (/var/task/node_modules/graphql/execution/execute.js:85:14)
         at execute (/var/task/node_modules/graphql/execution/execute.js:62:229)
         at graphqlImpl (/var/task/node_modules/graphql/graphql.js:86:31)
         at /var/task/node_modules/graphql/graphql.js:32:223
         at graphql (/var/task/node_modules/graphql/graphql.js:30:10)
       message: 'Cannot return null for non-nullable field Query.getDate.',
       locations: [Object],
       path: [Object] } ],
  data: null }
2019-02-25T10:07:16.340Z    9f75d1ea-2659-490b-ba59-5289a5d18d73    { Item: 
   { model: 'g5',
     transaction_date: '2018-07-05T09:30:31.391Z',
     id: '0f92fa40-8036-11e8-b106-952d7c9eb822@eu-west-1:ba1c96e7-92ff-4d63-879a-93d5e397b18a',
     make: 'moto' } }

Thanks in advance!


Solution

  • This is your code:

    const data = {
      getDate(args) {
        var params = {
            TableName: 'delete_this',
            Key: {
            "id": args.id
            }
        };
        client.get(params, function(err,data){
            if(err){
            console.log('error occured '+err)
            }else{
            console.log(data)
            }
        });
      },
    };
    const resolvers = {
      Query: {
        getDate: (root, args) => data.getDate(args),
      },
    };
    

    You're seeing that error because getDate is a a Non-Null field in your schema, but it is resolving to null. Your resolver needs to return either a value of the appropriate type, or a Promise that will resolve to that value. If you change data like this

    const data = {
      getDate(args) {
        return {
          id: 'someString',
          transaction_date: 'someString',
        }
      }
    }
    

    you'll see the error go away. Of course, your goal is to return data from your database, so we need to add that code back in. However, your existing code utilizes a callback. Anything you do inside the callback is irrelevant because it's ran after your resolver function returns. So we need to use a Promise instead.

    While you can wrap a callback with Promise, that shouldn't be necessary with aws-sdk since newer versions support Promises. Something like this should be sufficient:

    const data = {
      getDate(args) {
        const params = //...
        // must return the resulting Promise here
        return client.get(params).promise().then(result => {
          return {
            // id and transaction_date based on result
          }
        })
      }
    }
    

    Or using async/await syntax:

    const data = {
      async getDate(args) {
        const params = //...
        const result = await client.get(params).promise()
        return {
          // id and transaction_date based on result
        }
      }
    }