Accessing AWS DynamoDB through Apollo GraphQL Server deployed in AWS Lambda through Serverless

CSP
Level Up Coding
Published in
5 min readJan 3, 2021

--

Objective: Fetch all records of a DynamoDB table through a GraphQL lambda function.

Query:query {quotes {
id
value
source
}
}Response:{
"data": {
"quotes": [
{
"id": "q2",
"value": "If you don’t like how things are, change it! You’re not a tree.",
"source": "Jim Rohn"
},
{
"id": "q1",
"value": "Start with the end in mind.",
"source": "Stephen Covey"
}
]
}
}

Technologies used: AWS DynamoDB, AWS Lambda, AWS IAM, Serverless, Apollo Graphql

Prerequisite: Basic knowledge of AWS and Intermediate level knowledge of JavaScript, and Apollo Server.

STEP 1 — Create a DynamoDB table

First, create a table named Quote in DynamoDB with Primary Key id.

Create DynamoBD table

Add some entries to the table through Create item. You can use the below sample JSON text (instead of the Tree option on the dropdown)

{
"id": "q1",
"value": "Start with the end in mind.",
"source": "Stephen Covey"
}

Learn more about No SQL and DynamoDB here.

STEP 2 — Create AWS IAM user and configure AWS profile

To access any AWS service, we need to have an IAM user with appropriate access.

Go to AWS IAM console and add a user named serverless (this user will be leveraged by Serverless to connect to AWS services).

Select Access Type as Programmatic access

On Permissions, go to Attach Existing Policies Directly and give AdministratorAccess for now.

AdministratorAccess — Gives full access to all AWS resources. For a production application, you should provide fine-grained control as per the requirement

Continue through other steps with default values. On the last step, you will see the Access and Secret key. Download the .csv file or copy the values as you won't be able to access these afterward.

Now you need to configure this user in your machine. To do so, you need to install AWS CLI. The AWS Command Line Interface (CLI) is a unified tool to manage your AWS services.

Install CLI as per your OS.

On your terminal run aws configure --profile serverlessuser . Note the profile name is not the same as the IAM user name we created in the previous step. You can name it anything say serverlessprofile.

--profile — A named profile is a collection of settings and credentials that you can apply to an AWS CLI command. When you specify a profile to run a command, the settings and credentials are used to run that command. You can specify one profile that is the “default” and is used when no profile is explicitly referenced.

Read here for more details.

Run aws configure --profile serverlessuser on command prompt and provide access and secret key and few other details like region (for me I had us-east-1)

By now you should have two profiles default and serverlessuser in your system (you can check in your [HOMEDIR]/.aws/ )

Let’s first try to fetch data of this table from a locally running Apollo Server before we deploy the code to AWS.

STEP 3 — Apollo Server and GraphQL setup

Below is the bare minimum code to setup the apollo server, create the schema and fetch data from the Quote table.

If you are new to the apollo server, read this.

In a simplistic term, Apollo Server is a GraphQL compliant server that can be run standalone as well as in a serverless environment. In this step, we will run it as a standalone server and later will create a lambda function to run in the AWS lambda environment.

Create a folder and paste create a package.json and server.js file as below.

With below package.json do npm install . Notice it has some extra node modules which we will use later for creating the lambda function.

Create a file name server.js and run node server.js to start the server.

You should be able to now access the GraphQL instance at localhost:4000 and be able to query the quotes.

query {quotes {
id
value
source
}
}

The code is quite straightforward. You define a schema for quotes and the resolver calls getQuotes method where the actual code is to fetch the data.

Let's look at the key pieces of the code.

AWS provides SDKs for various languages to interact with AWS services. To access DynamoDB we leveraged @aws-sdk/client-dynamodb

const { DynamoDBClient, ScanCommand } = require(“@aws-sdk/client-dynamodb”);

By default, the DynamoDBClient will leverage the defaults profile to access AWS service

const client = new DynamoDBClient({ region: “us-east-1” });

ScanCommand is used to read all the records of the table. Here is the complete reference for all commands.

const results = await client.send(new ScanCommand(params));

The last key piece is

quotes.push(unmarshall(item));

unmarshall is DynamoDB util to convert the DynamoDB JSON format to plain JSON.

const { unmarshall } = require(“@aws-sdk/util-dynamodb”);

Since this post has become quite long will continue on the next post to see how to deploy this code as AWS lambda function through serverless. But before we end let’s see what marshalling and unmarshalling are?

DynamoDB converts Javascript types to DynamoDB AttributeValue

What does that mean? So in STEP 1, we added JSON text as simple key-value pair

{
"id": "q1",
"value": "Start with the end in mind.",
"source": "Stephen Covey"
}

But DynamoDB marshalls these JavaScript objects and introduces keys to identify the type of data. To see, do console.log(results.Items); after results are fetched.

//output
[{
id: { S: "q1" },
value: { S: "Start with the end in mind." },
source: { S: "Stephen Covey" }
}];

You would have noticed key namesS indicating the String type data marshalled into AttributeValues. So to unmarshall and get plain JSON we used the util unmarshall.

Hope this explains. You can read more here.

Hopefully, I didn't miss out on any key steps in here but in case I did please feel free to leave a comment. To get notified on the next part of the article to deploy this code as AWS lambda function follow me on medium or Twitter.

If you enjoyed this, please click the 👏 button and share to help others find it!

--

--

Striving to become my better self. I write on well researched thought provoking topics.