Accessing AWS DynamoDB through Apollo GraphQL Server deployed in AWS Lambda through Serverless
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.
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.
Update: Published Part 2 of the article to deploy this application as an AWS lambda function through Serverless
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!