๐ฐ Beginners new to AWS CDK, please do look at my previous articles one by one in this series.
If in case missed my previous article, do find it with the below links.
๐ Original previous post at ๐ Dev Post
๐ Reposted the previous post at ๐ dev to @aravindvcyber
In this article, we will be introducing a data access layer as a wrapper on top of our dynamodb table. Here specifically we have chosen graphql using AWS appsync to perform basic list items and get an item from dynamodb.
Construction ๐๏ธ
Let us start by creating a new file lib/appsync-stack.ts
for our new stack.
Imports used in this new stack โฉ๏ธ
Here we have imported the below objects to help us in our definition
import { Duration, Expiration, Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Table } from 'aws-cdk-lib/aws-dynamodb';
import { GraphqlApi, MappingTemplate, Schema, FieldLogLevel, AuthorizationType } from 'aws-lib-cdk/aws-appsync-alpha';
Appsync construct with the definition โบ
A new stack is created which is used to define our appsync endpoint as shown below.
Here we will be getting a default API key with an expiration of 7 days so that we can rotate this periodically. Besides that, we have logged our API sufficiently to understand the background process much better.
export class GqlStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const AppSyncApi = new GraphqlApi(this, 'gqlApi', {
name: 'gqlApi',
schema: Schema.fromAsset('assets/messages-schema.gql'),
xrayEnabled: true,
logConfig: {
excludeVerboseContent: false,
fieldLogLevel: FieldLogLevel.ALL,
},
authorizationConfig: {
defaultAuthorization: {
authorizationType: AuthorizationType.API_KEY,
apiKeyConfig: {
name: 'default-api-key',
description: 'default-api-key-description',
expires: Expiration.after(Duration.days(7))
}
}
}
})
}
}
Schema definition file ๐ข
You may also use the AWS console to update the schema before we update in CDK asset files when we know for sure.
type Message {
message: AWSJSON!
}
type MessagesTable {
createdAt: AWSTimestamp!
messageId: String!
event: Message
}
type MessagesTableConnection {
items: [MessagesTable]
nextToken: String
scannedCount: Int
}
type Query {
getMessage(messageId: String!, createdAt: AWSTimestamp!): MessagesTable
listMessages(filter: TableMessagesTableFilterInput, limit: Int, nextToken: String): MessagesTableConnection
}
input TableAWSTimestampFilterInput {
ne: AWSTimestamp
eq: AWSTimestamp
le: AWSTimestamp
lt: AWSTimestamp
ge: AWSTimestamp
gt: AWSTimestamp
contains: AWSTimestamp
notContains: AWSTimestamp
between: [AWSTimestamp]
}
input TableMessagesTableFilterInput {
createdAt: TableAWSTimestampFilterInput
messageId: TableStringFilterInput
}
input TableStringFilterInput {
ne: String
eq: String
le: String
lt: String
ge: String
gt: String
contains: String
notContains: String
between: [String]
beginsWith: String
}
Dynamodb connection as a data source ๐ถ
Here we are directly integrating dynamodb API with graphql as a data source
const messages = Table.fromTableName(this,'MessagesTableImport', 'MessagesTable');
const MessagesDS = AppSyncApi.addDynamoDbDataSource("MessagesDataSource", messages);
VTL Mapping template ๐ฉ๏ธ
Here we need to use VTL (Velocity Template Language) to transform/manipulate our request and the response we send/receive from the below resolvers. Using this can be a good strategy as this can be used in many places not only in appsync and API gateway.
You may also use the AWS console to test these transformations using the sample payload from logs before we update in CDK asset files.
Get message resolver ๐
Here you can also look into xray trace to understand when these blocks are utilized for getMessage
resolver
MessagesDS.createResolver({
typeName: 'Query',
fieldName: 'getMessage',
requestMappingTemplate: MappingTemplate.fromFile('assets/getMessageRequest.vtl'),
responseMappingTemplate: MappingTemplate.fromFile('assets/getMessageResponse.vtl'),
})
getMessageRequest VTL template ๐
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"messageId": $util.dynamodb.toDynamoDBJson($ctx.args.messageId),
"createdAt": $util.dynamodb.toDynamoDBJson($ctx.args.createdAt)
}
}
getMessageResponse VTL template โฑ๏ธ
#set($ctx.result.event = $util.parseJson($ctx.result.event))
$util.toJson($ctx.result)
List messages resolver ๐คก
Here you can also look into xray trace to understand when these blocks are utilized for listMessages
resolver
MessagesDS.createResolver({
typeName: 'Query',
fieldName: 'listMessages',
requestMappingTemplate: MappingTemplate.fromFile('assets/listMessagesRequest.vtl'),
responseMappingTemplate: MappingTemplate.fromFile('assets/listMessagesResponse.vtl'),
})
listMessagesRequest VTL template ๐
{
"version": "2017-02-28",
"operation": "Scan",
"filter": #if($context.args.filter) $util.transform.toDynamoDBFilterExpression($ctx.args.filter) #else null #end,
"limit": $util.defaultIfNull($ctx.args.limit, 20),
"nextToken": $util.toJson($util.defaultIfNullOrEmpty($ctx.args.nextToken, null)),
}
listMessagesResponse VTL template ๐ฃ
#set($children = [])
#foreach($item in $ctx.result.items)
#set($item.event = $util.parseJson($item.event))
$util.qr($children.add($item))
#end
#set($ctx.result.items = $children)
$util.toJson($ctx.result)
Client to explore graphQl โ๏ธ
Appsync Explorer Queries โจ๏ธ
In the AWS console, you can navigate the appsync and start querying. One advantage you have here is that we have cloud watch and tracing logs readily available if in case you want to check.
Apollo Studio Queries ๐๏ธ
But normally prefer the dark mode in apollo graphql studio, you may also try it out if you prefer that, maybe we would get that in the AWS console as well someday.
Conclusion ๐ซ
In this exercise, we have tried only the get and list operations to differentiate the effectiveness of the scan and query operation.
scannedCount
value in the above results shows the cost associated with list operation as the table gets bigger. I have removed the filter variable to show you what are the scanned records as shown below.
We will be refining this in our coming articles to achieve optimum speed and resource utilization.
We will be adding more connections to our stack and making it more usable in the upcoming articles by creating new constructs, so do consider following and subscribing to my newsletter.
โญ We have our next article in serverless, do check out
https://dev.to/aravindvcyber/aws-cdk-101-graphql-mutations-using-appsync-with-dynamodb-9n0
๐ Thanks for supporting! ๐
Would be great if you like to โ Buy Me a Coffee, to help boost my efforts ๐.
๐ Original post at ๐ Dev Post
๐ Reposted at ๐ dev to @aravindvcyber
๐ AWS CDK 101 - ๐ฒ GraphQL using AppSync with dynamodb
โ Aravind V (@Aravind_V7) May 30, 2022
{ by @Aravind_V7 }
Checkout more such in my pagehttps://t.co/CuYxnKr0Ighttps://t.co/phzOKFlXXO#aws #typescript #graphql #dynamodb #awscdk https://t.co/yeqeLZQt8A
Top comments (0)