๐ AWS CDK 101 - ๐ฒ dynamodb์ ํจ๊ป AppSync๋ฅผ ์ฌ์ฉํ๋ GraphQL
์ด์ ๊ธฐ์ฌ๋ฅผ ๋์น ๊ฒฝ์ฐ ์๋ ๋งํฌ์์ ์ฐพ์ผ์ญ์์ค.
๐ ๐์ ์๋ณธ ์ด์ ๊ฒ์๋ฌผDev Post
๐ ์ด์ ๊ฒ์๋ฌผ์ ๐์ ๋ค์ ๊ฒ์ํ์ต๋๋ค.
์ด ๊ธฐ์ฌ์์๋ dynamodb ํ ์ด๋ธ ์์ ๋ํผ๋ก โโ๋ฐ์ดํฐ ์ก์ธ์ค ๊ณ์ธต์ ์๊ฐํฉ๋๋ค. ์ฌ๊ธฐ์์๋ ํนํ ๊ธฐ๋ณธ ๋ชฉ๋ก ํญ๋ชฉ์ ์ํํ๊ณ dynamodb์์ ํญ๋ชฉ์ ๊ฐ์ ธ์ค๊ธฐ ์ํด AWS appsync๋ฅผ ์ฌ์ฉํ๋ graphql์ ์ ํํ์ต๋๋ค.
๊ฑด์ค ๐๏ธ
์ ์คํ์ ์ํ ์ ํ์ผ
lib/appsync-stack.ts
์ ์์ฑํ์ฌ ์์ํ๊ฒ ์ต๋๋ค.์ด ์๋ก์ด ์คํ์ ์ฌ์ฉ๋ ๊ฐ์ ธ์ค๊ธฐ โฉ๏ธ
์ฌ๊ธฐ์ ์ ์์ ๋์์ด ๋๋๋ก ์๋ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์์ต๋๋ค.
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 ๊ตฌ์ฑ
์๋์ ๊ฐ์ด appsync ๋์ ์ ์ ์ํ๋ ๋ฐ ์ฌ์ฉ๋๋ ์ ์คํ์ด ์์ฑ๋ฉ๋๋ค.
์ฌ๊ธฐ์์ ์ฃผ๊ธฐ์ ์ผ๋ก ๊ต์ฒดํ ์ ์๋๋ก ๋ง๋ฃ ๊ธฐ๊ฐ์ด 7์ผ์ธ ๊ธฐ๋ณธ API ํค๋ฅผ ๋ฐ๊ฒ ๋ฉ๋๋ค. ๊ทธ ์ธ์๋ ๋ฐฑ๊ทธ๋ผ์ด๋ ํ๋ก์ธ์ค๋ฅผ ํจ์ฌ ๋ ์ ์ดํดํ ์ ์๋๋ก API๋ฅผ ์ถฉ๋ถํ ๊ธฐ๋กํ์ต๋๋ค.
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))
}
}
}
})
}
}
์คํค๋ง ์ ์ ํ์ผ ๐ข
ํ์คํ๊ฒ ์๊ณ ์๋ ๊ฒฝ์ฐ CDK ์์ฐ ํ์ผ์์ ์ ๋ฐ์ดํธํ๊ธฐ ์ ์ AWS ์ฝ์์ ์ฌ์ฉํ์ฌ ์คํค๋ง๋ฅผ ์ ๋ฐ์ดํธํ ์๋ ์์ต๋๋ค.
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 ์ฐ๊ฒฐ ๐ถ
์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ dynamodb API๋ฅผ graphql๊ณผ ๋ฐ์ดํฐ ์์ค๋ก ์ง์ ํตํฉํ๊ณ ์์ต๋๋ค.
const messages = Table.fromTableName(this,'MessagesTableImport', 'MessagesTable');
const MessagesDS = AppSyncApi.addDynamoDbDataSource("MessagesDataSource", messages);
VTL ๋งคํ ํ ํ๋ฆฟ ๐ฉ๏ธ
์ฌ๊ธฐ์์ VTL(Velocity Template Language)์ ์ฌ์ฉํ์ฌ ์์ฒญ์ ๋ณํ/์กฐ์ํ๊ณ ์๋ ๋ฆฌ์กธ๋ฒ์์ ๋ณด๋ด๊ฑฐ๋ ๋ฐ๋ ์๋ต์ด ํ์ํฉ๋๋ค. ์ด๋ appsync ๋ฐ API ๊ฒ์ดํธ์จ์ด๋ฟ๋ง ์๋๋ผ ๋ง์ ๊ณณ์์ ์ฌ์ฉํ ์ ์์ผ๋ฏ๋ก ์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ ์ ๋ต์ด ๋ ์ ์์ต๋๋ค.
๋ํ AWS ์ฝ์์ ์ฌ์ฉํ์ฌ CDK ์์ฐ ํ์ผ์์ ์ ๋ฐ์ดํธํ๊ธฐ ์ ์ ๋ก๊ทธ์ ์ํ ํ์ด๋ก๋๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฌํ ๋ณํ์ ํ ์คํธํ ์ ์์ต๋๋ค.
๋ฉ์์ง ๋ฆฌ์กธ๋ฒ ๋ฐ๊ธฐ ๐
์ฌ๊ธฐ์์ xray ์ถ์ ์ ์กฐ์ฌํ์ฌ ์ด๋ฌํ ๋ธ๋ก์ด
getMessage
๋ฆฌ์กธ๋ฒ์ ํ์ฉ๋๋ ์๊ธฐ๋ฅผ ์ดํดํ ์ ์์ต๋๋ค.MessagesDS.createResolver({
typeName: 'Query',
fieldName: 'getMessage',
requestMappingTemplate: MappingTemplate.fromFile('assets/getMessageRequest.vtl'),
responseMappingTemplate: MappingTemplate.fromFile('assets/getMessageResponse.vtl'),
})
getMessageRequest VTL ํ ํ๋ฆฟ ๐
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"messageId": $util.dynamodb.toDynamoDBJson($ctx.args.messageId),
"createdAt": $util.dynamodb.toDynamoDBJson($ctx.args.createdAt)
}
}
getMessageResponse VTL ํ ํ๋ฆฟ โฑ๏ธ
#set($ctx.result.event = $util.parseJson($ctx.result.event))
$util.toJson($ctx.result)
๋ชฉ๋ก ๋ฉ์์ง ๋ฆฌ์กธ๋ฒ ๐คก
์ฌ๊ธฐ์์ xray ์ถ์ ์ ์กฐ์ฌํ์ฌ ์ด๋ฌํ ๋ธ๋ก์ด
listMessages
๋ฆฌ์กธ๋ฒ์ ํ์ฉ๋๋ ์๊ธฐ๋ฅผ ์ดํดํ ์ ์์ต๋๋ค.MessagesDS.createResolver({
typeName: 'Query',
fieldName: 'listMessages',
requestMappingTemplate: MappingTemplate.fromFile('assets/listMessagesRequest.vtl'),
responseMappingTemplate: MappingTemplate.fromFile('assets/listMessagesResponse.vtl'),
})
listMessagesRequest VTL ํ ํ๋ฆฟ ๐
{
"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 ํ ํ๋ฆฟ ๐ฃ
#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)
graphQl โ๏ธ์ ํ์ํ๋ ํด๋ผ์ด์ธํธ
Appsync ํ์๊ธฐ ์ฟผ๋ฆฌ โจ๏ธ
AWS ์ฝ์์์ appsync๋ฅผ ํ์ํ๊ณ ์ฟผ๋ฆฌ๋ฅผ ์์ํ ์ ์์ต๋๋ค. ์ฌ๊ธฐ์ ์๋ ํ ๊ฐ์ง ์ฅ์ ์ ํ์ธํ๋ ค๋ ๊ฒฝ์ฐ์ ๋๋นํ์ฌ ํด๋ผ์ฐ๋ ๊ฐ์ ๋ฐ ์ถ์ ๋ก๊ทธ๋ฅผ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ๋๋ค.
์ํด๋ก ์คํ๋์ค ์ฟผ๋ฆฌ ๐๏ธ
๊ทธ๋ฌ๋ ์ผ๋ฐ์ ์ผ๋ก apollo graphql ์คํ๋์ค์์ ์ด๋์ด ๋ชจ๋๋ฅผ ์ ํธํฉ๋๋ค. ์ํ๋ ๊ฒฝ์ฐ ์๋ํด ๋ณผ ์๋ ์์ต๋๋ค. ์ธ์ ๊ฐ๋ AWS ์ฝ์์์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๊ฒฐ๋ก ๐ซ
์ด ์ฐ์ต์์๋ ๊ฒ์ ๋ฐ ์ฟผ๋ฆฌ ์์ ์ ํจ์จ์ฑ์ ์ฐจ๋ณํํ๊ธฐ ์ํด get ๋ฐ list ์์ ๋ง ์๋ํ์ต๋๋ค.
scannedCount
์์ ๊ฒฐ๊ณผ ๊ฐ์ ํ
์ด๋ธ์ด ์ปค์ง์๋ก ๋ฆฌ์คํธ ์ฐ์ฐ์ ๋๋ ๋น์ฉ์ ๋ํ๋
๋๋ค. ์๋์ ๊ฐ์ด ์ค์บํ ๋ ์ฝ๋๊ฐ ๋ฌด์์ธ์ง ๋ณด์ฌ์ฃผ๊ธฐ ์ํด ํํฐ ๋ณ์๋ฅผ ์ ๊ฑฐํ์ต๋๋ค.์ต์ ์ ์๋์ ๋ฆฌ์์ค ํ์ฉ์ ๋ฌ์ฑํ๊ธฐ ์ํด ๋ค์ ๊ธฐ์ฌ์์ ์ด๋ฅผ ๊ฐ์ ํ ๊ฒ์ ๋๋ค.
์ฐ๋ฆฌ๋ ์คํ์ ๋ ๋ง์ ์ฐ๊ฒฐ์ ์ถ๊ฐํ๊ณ ์๋ก์ด ๊ตฌ์ฑ์ ๋ง๋ค์ด ๋ค์ ๊ธฐ์ฌ์์ ๋ ์ ์ฉํ๊ฒ ๋ง๋ค ๊ฒ์ด๋ฏ๋ก ์ ๋ด์ค๋ ํฐ๋ฅผ ํ๋ก์ฐํ๊ณ ๊ตฌ๋ ํ๋ ๊ฒ์ ๊ณ ๋ คํ์ญ์์ค.
โญ ์๋ฒ๋ฆฌ์ค์ ๋ํ ๋ค์ ๊ธฐ์ฌ๊ฐ ์์ต๋๋ค. ํ์ธํ์ญ์์ค.
๐ ์์ํด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค! ๐
โ Buy Me a Coffee์ ์ํ์๋ฉด ์ ๋ ธ๋ ฅ์ ๐.
๐ ์๋ณธ ๊ฒ์๋ฌผ ๐Dev Post
๐ Reposted at ๐
๐ AWS CDK 101 - ๐ฒ GraphQL using AppSync with dynamodb
โ Aravind V (@Aravind_V7)
{ by }
Checkout more such in my pagehttps://t.co/CuYxnKr0Ighttps://t.co/phzOKFlXXO https://t.co/yeqeLZQt8A
Reference
์ด ๋ฌธ์ ์ ๊ดํ์ฌ(๐ AWS CDK 101 - ๐ฒ dynamodb์ ํจ๊ป AppSync๋ฅผ ์ฌ์ฉํ๋ GraphQL), ์ฐ๋ฆฌ๋ ์ด๊ณณ์์ ๋ ๋ง์ ์๋ฃ๋ฅผ ๋ฐ๊ฒฌํ๊ณ ๋งํฌ๋ฅผ ํด๋ฆญํ์ฌ ๋ณด์๋ค https://dev.to/aravindvcyber/aws-cdk-101-graphql-using-appsync-with-dynamodb-16ddํ ์คํธ๋ฅผ ์์ ๋กญ๊ฒ ๊ณต์ ํ๊ฑฐ๋ ๋ณต์ฌํ ์ ์์ต๋๋ค.ํ์ง๋ง ์ด ๋ฌธ์์ URL์ ์ฐธ์กฐ URL๋ก ๋จ๊ฒจ ๋์ญ์์ค.
์ฐ์ํ ๊ฐ๋ฐ์ ์ฝํ ์ธ ๋ฐ๊ฒฌ์ ์ ๋ (Collection and Share based on the CC Protocol.)
์ข์ ์นํ์ด์ง ์ฆ๊ฒจ์ฐพ๊ธฐ
๊ฐ๋ฐ์ ์ฐ์ ์ฌ์ดํธ ์์ง
๊ฐ๋ฐ์๊ฐ ์์์ผ ํ ํ์ ์ฌ์ดํธ 100์ ์ถ์ฒ ์ฐ๋ฆฌ๋ ๋น์ ์ ์ํด 100๊ฐ์ ์์ฃผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์ ํ์ต ์ฌ์ดํธ๋ฅผ ์ ๋ฆฌํ์ต๋๋ค