DEV Community

Cover image for ๐Ÿ„ AWS CDK 101 - ๐Ÿฒ GraphQL using AppSync with dynamodb
Aravind V
Aravind V

Posted on • Updated on • Originally published at devpost.hashnode.dev

๐Ÿ„ AWS CDK 101 - ๐Ÿฒ GraphQL using AppSync with dynamodb

๐Ÿ”ฐ 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.

gql front

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';
Enter fullscreen mode Exit fullscreen mode

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))
              }
          }
      }
    })

  }
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

GQL visual

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.

create test

run test

resolvers

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'),
})
Enter fullscreen mode Exit fullscreen mode

getMessageRequest VTL template ๐ŸŒŸ

{
    "version": "2017-02-28",
    "operation": "GetItem",
    "key": {
        "messageId": $util.dynamodb.toDynamoDBJson($ctx.args.messageId),
        "createdAt": $util.dynamodb.toDynamoDBJson($ctx.args.createdAt)
    }
}
Enter fullscreen mode Exit fullscreen mode

getMessageResponse VTL template โ›ฑ๏ธ


#set($ctx.result.event = $util.parseJson($ctx.result.event))

$util.toJson($ctx.result)

Enter fullscreen mode Exit fullscreen mode

get message xray

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'),
})
Enter fullscreen mode Exit fullscreen mode

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)),
}
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

list message xray

Client to explore graphQl โ„๏ธ

client

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.

appsync explorer get

appsync explorer list

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.

appollo get

appollo list

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.

list view

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 ๐Ÿ˜.

Buy Me a Coffee at ko-fi.com

๐Ÿ” Original post at ๐Ÿ”— Dev Post

๐Ÿ” Reposted at ๐Ÿ”— dev to @aravindvcyber


๐Ÿ„ AWS CDK 101 - ๐Ÿฒ GraphQL using AppSync with dynamodb
{ by @Aravind_V7 }

Checkout more such in my pagehttps://t.co/CuYxnKr0Ighttps://t.co/phzOKFlXXO#aws #typescript #graphql #dynamodb #awscdk https://t.co/yeqeLZQt8A

โ€” Aravind V (@Aravind_V7) May 30, 2022

Top comments (0)