Creating a Calculated Field in GraphQL Using a Custom Resolver and Dgraph Lambda

Most of the time the data stored in a database is static. The data we put into the database is the data that we retrieve with our GraphQL query. But what about those times we need something a bit more dynamic? That is where we can leverage a solution like Dgraph Lambda to bring business logic directly into our GraphQL schema.

In this blog, we will go over a simple example of a calculated field. We will take an array of numbers stored in a field and return the average of that array. Although the example is not complex, it will show you the basics and give you a good foundation to build more complex logic using Dgraph Lambda.

You can check out the accompanying video for this article from our YouTube channel below:

Creating a dynamically calculated field

For this first example, we will start extremely simple. What we will accomplish is taking a Float array stored in the database and calculating the average of it. The average itself will not be stored in the database but will be returned through a GraphQL query as if it is. This will be transparent to the user and powered by Dgraph Lambda.

The GraphQL schema will look like this:

type Student {
  id: ID
  name: String!
  grades: [Float] 
  gradeAverage: Float @lambda
}

This schema contains a Student type with a few fields. Notice the gradeAverage field: we’ve annotated it with a @lambda directive. The @lambda directive tells Dgraph that this field will get resolved by some custom JavaScript inside Dgraph Lambda.

In Dgraph Cloud, navigate to the Schema screen, add this schema to the textbox, and click Deploy. This will deploy the schema to Dgraph and get your GraphQL endpoint ready.

At this point, we need to create our custom logic within Dgraph Lambda that will power this field. For that, we will loop through all of the Float entries in the array, add them together, and divide by the total number of entries to get the average. That logic will look like this:

const gradeAverageResolver = ({parent: {grades}}) => {
   var total = 0;
   for(var i = 0; i < grades.length; i++) {
       total += grades[i];
   }
   return total / grades.length;
}

self.addGraphQLResolvers({
   "Student.gradeAverage": gradeAverageResolver
})

In this logic, you’ll see that we have created a function called gradeAverageResolver that gets the grades array from the parent type. It then returns the average of the grades.

In Dgraph Cloud, navigate to the Lambda screen, add in the above code, and click Save. This will make your Lambda go live!

Lastly, we add the resolver to the gradeAverage field using the self.addGraphQLResolvers function. This will bind this function to the field in the GraphQL schema.

With our logic and schema in place, we can now issue a mutation to add some data and bring back our calculated field in the return object. Here’s an example mutation to try out:

mutation MyMutation {
  addStudent(input: {name: "Diggy McDgraph", grades: [65, 61.2, 72, 91, 99.9]})
  {
      student {
      name
      grades
      gradeAverage
    }
  }
}

In Dgraph Cloud, navigate to the GraphQL screen, add the above mutation to the text area, and click the Play button at the top of the screen.

The response should look like this:

Dgraph Cloud GraphQL screen showing the above mutation and its response

Congratulations! You just created your first calculated field in GraphQL using Dgraph Lambda! Now that you know the basics, you can dig further into our Dgraph Lambda docs and previous blogs containing more examples on Dgraph Lambda. When it comes to adding custom logic to your GraphQL endpoint, no solution is more simple than using Dgraph Lambda and JavaScript. Stay tuned for further blogs where we explore even more ways to build and customize logic in GraphQL services.