Better Lambda Logging/Debugging

I am working on trying to integrate some business logic into a mutation to create a response to a poll in my application. Specifically, I would like to do the following:

  1. Ensure the person hasn’t already voted
  2. Ensure the poll is still open
  3. Ensure the vote given is a valid option
  4. Increment vote counts on the poll and vote option

To do so I am trying a Lambda function with graphql queries. Below is the relevant schema, lambda and an example mutaiton call:

type Option implements Metadata {
    optionID: ID!
    poll: Poll
    outcome: ResultOutcome!
    correct: Boolean
    voteCount: Int
}

type Poll {
    pollID: ID!
    title: String! @search
    options: [Option!]
    totalVotes: Int!
    votingOpen: Boolean! @search
    pollResolved: Boolean! @search
    correctOption: Option
    pollResponses: [PollResponse!] @hasInverse(field: poll)
}

type PollResponse implements Metadata {
    pollResponseID: ID!
    poll: Poll!
    voter: User!
    vote: Option!
    correct: Boolean @search
    score: Float
}

type Mutation {
    newPollResponse(pollID: ID!, optionID: ID!, userID: ID!): PollResponse @lambda
}
async function newPollResponse({args, graphql}) {
    const dateCreated = new Date().toISOString();
    const poll = await graphql(`query($pollID: ID!, $optionID: [ID!]) {
        getPoll(pollID: $pollID) {
            totalVotes
            votingOpen
            options(filter: {optionID: $optionID}) {
                optionID
                voteCount
            }
        }
    }`, {"pollID": args.pollID, "optionID": [args.optionID]})

    // Only continue if option is present on poll and voting is open on poll
    if (poll.data.getPoll.options.length === 1 && poll.data.getPoll.votingOpen) {
        const user = await graphql(`query($userID: ID!, $pollID: [ID!]) {
            getUser(userID: $userID) {
              pollResponses {
                poll(filter: {pollID: $pollID}) {
                  pollID
                }
              }
            }
        }`, {"userID": args.userID, "pollID": [args.pollID]})

        // Only continue if user hasn't already voted
        if (!user.data.getUser.pollResponses) {
            const newOptionCount = poll.data.getPoll.options[0].voteCount + 1;
            const newPollCount = poll.data.getPoll.totalVotes + 1;

            // Add poll response
            const pollResponse = await graphql(`mutation($pollID: ID!, $optionID: ID!, $userID: ID!, $dateCreated: DateTime! $newPollCount: Int!, $newOptionCount: Int!) {
                addPollResponse(input: {poll: {pollID: $pollID}, vote: {optionID: $optionID}, voter: {userID: $userID}, dateCreated: $dateCreated}) {
                  pollResponse {
                    pollResponseID
                    voter {
                      username
                    }
                    vote {
                      optionID
                    }
                  }
                }
                updatePoll(input: {filter: {pollID: [$pollID]}, set: {totalVotes: $newPollCount}}) {
                  poll {
                    pollID
                  }
                }
                updateOption(input: {filter: {optionID: [$optionID]}, set: {voteCount: $newOptionCount}}) {
                  option {
                    optionID
                  }
                }
            }`, {"pollID": args.pollID, "optionID": args.optionID, "userID": args.userID, "dateCreated": dateCreated, "newPollCount": newPollCount, "newOptionCount": newOptionCount})
            return pollResponse.data.addPollResponse.pollResponse;
        }
    }
}

self.addGraphQLResolvers({
    "Mutation.newPollResponse": newPollResponse,
})
mutation {
  newPollResponse(pollID: somePollID, optionID: someOptionID, userID: someUserID) {
    pollResponseID
    vote {
      optionID
      outcome {
        win
      }
    }
    voter {
      username
      userID
      email
    }
  }
}

When I run this query, I keep getting the following error:

{
  "errors": [
    {
      "message": "Evaluation of custom field failed because external request returned an error: unexpected error with: 400 for field: newPollResponse within type: Mutation.",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ],
  "data": {
    "newPollResponse": null
  },
  "extensions": {
    "tracing": {
      "version": 1,
      "startTime": "2021-03-21T01:14:44.877907688Z",
      "endTime": "2021-03-21T01:14:44.945207546Z",
      "duration": 67299879
    }
  }
}

The Lambda logs show no information. This is very difficult to debug. Is there a way I can get a better idea of what error I am encountering? Or can someone tell me if I am approaching this Lambda in the wrong way?

I’ve found it frustrating to be able to build this kind of simple business logic into my application. I came to DGraph from FaunaDB and I like it better in almost every way except for in this area, where FaunaDB has a more user-friendly/intuitive query language (FQL) for implementing this logic and queries can actually be written with a JS driver. I’d love to feel more comfortable doing this kind of thing with DGraph, so any help is appreciated.

Thanks!

1 Like

After some effort I was able to debug the problem and get the lambda working as expected. It would still be nice to have a better way to diagnose problems, and I would appreciate any input on if I am going about this type of thing correctly.

Sad that there’s been no official response to this given some of the outstanding issues with GraphQL mutations/auth and lambdas being the go-to suggestion to work around them.

1 Like