GraphQL and Sequelize doesn't return inserted object

I'm stuck on an error on my GraphQL and Sequelize backend, for some reason my mutation doesn't return the data, even though I guarantee there's data being returned inside my resolver. I feel like this is probably something small that I'm missing, but I've been stuck for awhile.

The Sequelize part works, the object is indeed inserted, however the return is always a null object.

Here's my mutation:

mutation {
  createUserVoucher(pinId: 1, voucherId: 1) {
    id
  }
}

Here's the return:

{
  "data": {
    "createUserVoucher": {
      "id": null
    }
  }
}

Here's my resolver:

createUserVoucher: (parent, args, { user, models }) => {
  args['userId'] = user.id;
  models.UserVoucher.count({
    where: {utilized: true, pinId: args.pinId, userId: args.userId}
  }).then( c => {
    if (c > 0) {
      return []
    } else {
      models.Voucher.findOne({
        where: {
          id: args.voucherId
        }
      }).then( voucher => {
        models.UserVoucher.count({
          where: { voucherId: args.voucherId }
        }).then( c => {
            return models.UserVoucher.create(args)
        })
      })
    }
  });
  return []
}

UserVoucher definition:

type UserVoucher {
  id: Int
  nodeId: Int!
  userId: ID!
  voucherId: ID!
  voucher: Voucher
  pinId: ID!
  capturedAt: DateTime
  utilized: Boolean
}
`;

Mutation definition:

createUserVoucher(
  pinId: Int!, 
  voucherId: Int!
): UserVoucher

Any ideas on what I'm missing? It will be much appreciated, thank you very much!! Also if any more information is needed, let me know!

1 answer

  • answered 2018-03-14 00:44 Daniel Rearden

    You're missing three returns:

    createUserVoucher: (parent, args, { user, models }) => {
      args['userId'] = user.id;
      return models.UserVoucher.count({ <----- HERE
        where: {utilized: true, pinId: args.pinId, userId: args.userId}
      }).then( c => {
        if (c > 0) {
          return []
        } else {
          return models.Voucher.findOne({ // <----- HERE
            where: {
              id: args.voucherId
            }
          }).then( voucher => {
            return models.UserVoucher.count({ // <----- AND HERE
              where: { voucherId: args.voucherId }
            }).then( c => {
                return models.UserVoucher.create(args)
            })
          })
        }
      });
      return []
    }
    

    When chaining promises, it's important to remember to always return any additional promises inside each then call -- otherwise the promise is fired but it's not awaited.

    Couple of additional notes:

    While strictly not hurting anything, you should return null instead of an empty array inside your resolver. According to your schema, your mutation returns a nullable UserVoucher object. Returning an empty array is misleading to anyone reading your code because it implies this resolver should be returning a array.

    The results from the second UserVoucher.count call and the Voucher.findOne call aren't used, which means they might not be necessary?

    Lastly, you can also significantly clean up your code by using async/await:

    createUserVoucher: async (parent, args, { user, models }) => {
      args['userId'] = user.id;
      const c = await models.UserVoucher.count({
        where: {utilized: true, pinId: args.pinId, userId: args.userId}
      })
      if (c > 0) return null
      const voucher = await models.Voucher.findOne({
        where: { id: args.voucherId }
      })
      const c2 = await models.UserVoucher.count({ 
        where: { voucherId: args.voucherId }
      })
      return models.UserVoucher.create(args) // still need a return here
    }