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:
- Ensure the person hasn’t already voted
- Ensure the poll is still open
- Ensure the vote given is a valid option
- 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!