In this blog, we will learn about lambda which gives us the ability to execute custom resolvers in JavaScript, and how easy it is to get started with it on Slash GraphQL.
We will also learn how to create a local setup to manage our lambda script and schema with the help of the Slash GraphQL CLI tool to make the developer experience much smoother.
You can find the complete source code for this example here on GitHub.
What is Lambda?
Lambda offers a way to write your custom logic in JavaScript. It integrates with your GraphQL schema for easy execution in a GraphQL API.
- Slash GraphQL users don’t require any setup, which we will be using in this blog (To use locally with Dgraph you need to setup a Dgraph cluster with a working lambda server)
- Declare lambda queries, mutations, and fields in your GraphQL schema as needed
- Define lambda resolvers for them in a JavaScript file
It simplifies the job of developers, as they can build a complex backend that is rich with business logic, without setting up multiple different services. Also, you can build your backend in JavaScript, which means you can build both your frontend and backend using the same language.
Dgraph doesn’t execute your custom logic itself. It makes external HTTP requests to a user-defined lambda server. Slash GraphQL will do all of this for you, which we will be using in this blog.
There are three places where you can use the lambda directive and thus tell Dgraph where to apply custom JavaScript logic. We will use each of them in this blog.
- Lambda fields to your types and interfaces
- Lambda queries to the Query type
- Lambda mutations to the Mutation type
Deploy a GraphQL backend on Slash GraphQL
You’ll need an account to create GraphQL backends on Slash GraphQL. If you don’t have an account, head over to https://slash.dgraph.io and register for your free account.
Create a GraphQL Deployment
You’ll see the empty dashboard screen when you first log into Slash GraphQL.
Just press the “Launch a backend” button. That takes you to a screen to create the backend. You can also check out the “Interactive Tutorial” if you like.
I named my deployment lambda-example
, set it up in AWS US West region, and selected the Free
billing plan. Clicking “Launch” spins up the backend infrastructure to serve the GraphQL app. That’ll spin for just a few moments, and once you have the green tick, it’s live.
While it’s spinning up, note down the URL of your GraphQL API. You’ll need that to connect it to the app.
That’s it — the GraphQL API for the app is up and running and you can now connect to it via the Slash GraphQL CLI by using the endpoint URL. But first, let’s create our schema.
Create Schema
To see it in action, this lambda example is built on a basic schema that stores football player details.
Let’s create a basic schema that stores football player details such as name, country, club, etc. The schema contains a single type Player
, add more fields like pace, shooting, defending, etc.
Now using those fields we want to compute an overall for the player which you would have seen if you have ever played FIFA. Here comes the chance for lambda to shine, we will use it with the field overall
.
Updated schema -
type Player {
id: ID!
name: String! @search(by: [fulltext])
position: String! @search
pace: Int!
shooting: Int!
passing: Int!
dribbling: Int!
defending: Int!
physical: Int!
overall: Int @lambda
club: String
country: String
}
Next up, let’s create a basic local setup.
Local setup
- Create a folder
dgraph-lambda
and then store the above GraphQL schema in a file calledschema.graphql
. - Run
npm init
to create a package file since we want to learn how to use npm packages with lambda and npm scripts to make it easier to manage our Slash GraphQL instance. - Create an empty file for storing the lambda script
src/index.js
. - We will be using the Slash GraphQL CLI so let’s install that first.
npm install -g slash-graphql
- We need to provide the Slash GraphQL endpoint for performing actions on our instance, let’s store that in
package.json
asconfig
object which is accessible by the npm scripts.
"name": "dgraph-lambda",
"version": "1.0.0",
"description": "",
"main": "index.js",
"config": {
"url": "YOUR-SLASH-GRAPHQL-ENDPOINT"
},
- Let’s add some helper npm scripts like for bundling the lambda script file (this is needed if you’re using an npm package) using webpack, submitting updated schema to Slash GraphQL. Observe how the config object is accessible within the npm scripts and see how
push-lambda
npm script first runs webpack with targetwebworker
to generate the bundledist/main.js
which is then used byslash-update-lambda
to submit it to Slash GraphQL.
"scripts": {
"slash-login": "slash-graphql login",
"push-schema": "slash-graphql update-schema -e $npm_package_config_url schema.graphql",
"slash-update-lambda": "slash-graphql update-lambda -e $npm_package_config_url -f=dist/main.js",
"push-lambda": "npx webpack --target=webworker && npm run slash-update-lambda",
"slash-drop-data": "slash-graphql drop -e $npm_package_config_url -d"
},
- Let’s log in and submit the schema -
npm run slash-login npm run push-schema
Create lambda field resolver
Let’s create the script which will have the function for calculating the player’s overall
. We need access to the fields for the current object to calculate the overall
this can be achieved by using the parent
object that is accessible to lambda. This function as you can see below returns the calculated overall
value for the object.
Now we need a way to add it as a resolver, this can be achieved by using self.addGraphQLResolvers
. Refer the docs for more info.
Added the npm package chalk
to just demonstrate the process of adding an npm package to the lambda script.
npm install chalk --save
Update src/index.js
with this -
const chalk = require("chalk");
async function overall({ parent }) {
console.log(chalk.blue("Test package"));
let paceWeight,
shootingWeight,
passingWeight,
dribblingWeight,
defenseWeight,
physicalWeight = 0;
if (parent.position == "Forward") {
paceWeight = 0.3;
shootingWeight = 0.25;
passingWeight = 0.1;
dribblingWeight = 0.25;
defenseWeight = 0.03;
physicalWeight = 0.07;
} else if (parent.position == "Midfield") {
paceWeight = 0.1;
shootingWeight = 0.15;
passingWeight = 0.35;
dribblingWeight = 0.2;
defenseWeight = 0.1;
physicalWeight = 0.1;
} else if (parent.position == "Defense") {
paceWeight = 0.05;
shootingWeight = 0.05;
passingWeight = 0.1;
dribblingWeight = 0.1;
defenseWeight = 0.4;
physicalWeight = 0.3;
}
return Math.round(
parent.pace * paceWeight +
parent.shooting * shootingWeight +
parent.passing * passingWeight +
parent.dribbling * dribblingWeight +
parent.defending * defenseWeight +
parent.physical * physicalWeight
);
}
self.addGraphQLResolvers({
"Player.overall": overall,
});
Submit lambda script to Slash GraphQL -
npm run push-lambda
NOTE: Updating the lambda script may take up to one minute to complete
Let’s add a few players and see the above lambda in action!
Go to the API Explorer in the Slash GraphQL interface or use any GraphQL client like Postman, Insomnia, or GraphQL playground.
mutation addPlayers($players: [AddPlayerInput!]!) {
addPlayer(input: $players) {
player {
name
pace
passing
overall
id
}
}
}
Query Variables -
{
"players": [
{
"name": "Auba",
"position": "Forward",
"pace": 92,
"shooting": 90,
"passing": 85,
"dribbling": 82,
"defending": 80,
"physical": 80,
"club": "Arsenal",
"country": "Gabon"
},
{
"name": "Saka",
"position": "Midfield",
"pace": 92,
"shooting": 87,
"passing": 85,
"dribbling": 84,
"defending": 85,
"physical": 82,
"club": "Arsenal",
"country": "England"
},
{
"name": "Rowe",
"position": "Midfield",
"pace": 85,
"shooting": 85,
"passing": 90,
"dribbling": 82,
"defending": 78,
"physical": 75,
"club": "Arsenal",
"country": "England"
},
{
"name": "Willian",
"position": "Midfield",
"pace": 85,
"shooting": 70,
"passing": 68,
"dribbling": 68,
"defending": 67,
"physical": 65,
"club": "Arsenal",
"country": "Brazil"
}
]
}
Create lambda mutation resolver
We can use lambda for mutations and queries as well. At the start of the transfer window every team is looking to strengthen their squad, let’s add a Transfer
type that keeps track of the transfer requests.
We would like to inform the player’s agent by contacting them about our interest in buying the player this can be achieved by using a lambda mutation resolver which sends the transfer request in form of a mail/message.
Let’s update the schema to include the Mutation
type with a sendTransferRequest
mutation which takes the player’s name and the current club as input then add the lambda directive.
Updated schema -
type Player {
...
}
type Transfer {
id: ID!
player: String!
currentclub: String!
}
type Mutation {
sendTransferRequest(player: String!, currentclub: String!): ID! @lambda
}
Submit the updated schema-
npm run push-schema
Updated lambda script -
const chalk = require("chalk");
async function overall({ parent }) {
...
}
async function sendTransferRequest({ args, graphql }) {
// Can send email/message to the player's agent by calling a service here
const results = await graphql(
`
mutation($player: String!, $currentclub: String!) {
addTransfer(input: [{ player: $player, currentclub: $currentclub }]) {
transfer {
id
player
currentclub
}
}
}
`,
{ player: args.player, currentclub: args.currentclub }
);
return results.data.addTransfer.transfer[0].id;
}
self.addGraphQLResolvers({
"Player.overall": overall,
"Mutation.sendTransferRequest": sendTransferRequest,
});
Submit the updated script -
npm run push-lambda
NOTE: Updating the lambda script may take up to one minute to complete
Time to send a transfer request for a player we want!
mutation sendTransferReq {
sendTransferRequest(player: "Aouar", currentclub: "Lyon")
}
Create lambda query resolver
Lambda offers a way to run DQL. Let’s get the list of top forward players who have shooting
higher than 80 using a lambda query that executes a DQL query.
Let’s update the schema to include the Query
type with a topForwardPlayers
query which returns a list of players then add the lambda directive.
For using DQL on Slash GraphQL we need to change the backend mode to Flexible
from the Advanced
tab of the Settings
option.
Updated schema -
type Player {
...
}
type Transfer {
...
}
type Mutation {
...
}
type Query {
topForwardPlayers: [Player] @lambda
}
Submit the updated schema-
npm run push-schema
Updated lambda script -
const chalk = require("chalk");
async function overall({ parent }) {
...
}
async function sendTransferRequest({ args, graphql }) {
...
}
async function topForwardPlayers({ dql }) {
// DQL query for players with shooting higher than 80
const results = await dql.query(`query queryPlayer {
queryPlayer(func: type(Player), orderdesc: Player.shooting) @filter(ge(Player.shooting, 80)){
name: Player.name
position: Player.position
shooting: Player.shooting
passing: Player.passing
club: Player.club,
country: Player.country
}
}`);
return results.data.queryPlayer;
}
self.addGraphQLResolvers({
"Player.overall": overall,
"Mutation.sendTransferRequest": sendTransferRequest,
"Query.topForwardPlayers": topForwardPlayers,
});
Submit the updated script -
npm run push-lambda
NOTE: Updating the lambda script may take up to one minute to complete
Let’s again ahead over to API Explorer in the Slash GraphQL interface and try the lambda query -
query topForwardPlayers{
topForwardPlayers {
name
position
shooting
passing
}
}
Summary
We learned how easy it is to use lambda on Slash GraphQL. Using npm packages makes it even more powerful and makes it easier to add business logic to your backend. Managing your instance with Slash GraphQL CLI is fast, too!
Check out the code used in this blog here. If you’re new to GraphQL or graph databases, Dgraph Learn has guided tutorials to walk you through the fundamentals. Signup on Slash GraphQL and give it a try, if you haven’t already!
ReferencesLambda docs: https://dgraph.io/docs/graphql/lambda/overview/ Slash GraphQL CLI docs: https://dgraph.io/docs/slash-graphql/slash-cli/overview/ DQL docs: https://dgraph.io/docs/query-language/graphql-fundamentals/ NPM scripts docs: https://docs.npmjs.com/cli/v6/using-npm/scriptsThis is a companion discussion topic for the original entry at https://dgraph.io/blog/post/lambda-slash-graphql/