0

I'm trying to create a mutation in GraphQL that charges the user with Stripe but I can't get the user back client side. Everything works well in my database, the payment is done but on my client side the .then() is firing too early with a result of null while it should return me the edited user. It's actually firing before the stripe.charges has finished on my server.

Server side :

chargeUser(args) {
    const { userId, membershipId, stripeToken } = args;

    return User.findById(userId)
        .then((user) => {
            return Membership.findById(membershipId)
                .then((membership) => {
                    return stripe.charges.create({
                        amount: membership.price * 100,
                        currency: 'chf',
                        source: stripeToken,
                        description: `${user.firstname} ${user.lastname}`
                    }, function(err) {
                        if (!err) {
                            user.membership = membershipId;
                            return user.save();
                        } else {
                            console.log(err)
                        }
                    });
                })
        });
}

client side :

this.props.mutate({
    variables: {
        membershipId: this.props.membershipId,
        userId: global.userId,
        stripeToken: token.tokenId
    }
})
.then((res) => {
    // Returning null before the stripe.charges has finished
    console.log(res)
})
Nicolas Meienberger
  • 777
  • 2
  • 8
  • 18

1 Answers1

1

The problem here is that stripe.charges.create() utilizes a callback; it does not return a promise. Unlike a promise, returning the user inside the callback does not do anything -- your promise chain terminates at the return value of stripe.charges.create(), which is null.

In order to make your resolver wait for the callback, you have to wrap it within a promise, like this:

return User.findById(userId)
  .then((user) => {
    return Membership.findById(membershipId)
      .then((membership) => {
        return new Promise((resolve, reject) => {
          stripe.charges.create({
            amount: membership.price * 100,
            currency: 'chf',
            source: stripeToken,
            description: `${user.firstname} ${user.lastname}`
          }, (err) => {
            err ? reject(err) : resolve()
          })
        })
      })
      .then(() => user.save())
  })

Or, cleaned up a little bit with async/await:

const chargeUser = async (args) => {
    const { userId, membershipId, stripeToken } = args;

    const user = await User.findById(userId)
    const membership = await Membership.findById(membershipId)
    await new Promise((resolve, reject) => {
      stripe.charges.create({
        amount: membership.price * 100,
        currency: 'chf',
        source: stripeToken,
        description: `${user.firstname} ${user.lastname}`
      }, (err) => {
        err ? reject(err) : resolve()
      })
    })
    return user.save()
}
Daniel Rearden
  • 80,636
  • 11
  • 185
  • 183