こんにちは!
最近どんどん AppSync の熱が上がってきている当ブログです。今回は AppSyncを理解するために CloudFormation での構成を解説していきます。
AppSync に興味のある方、ぜひご注目いただければ幸いです。
AppSync のリソースタイプは7つあります。CloudFormation ではこれらを組み合わせ AppSync を構成していきます。
本記事では、どの記述が何を行っているかを理解するため、それぞれのリソースごとに解説していきます。最後に全リソースをデプロイするサンプルコードを用意しておりますので、こちらもぜひ参考にしてください。
CloudFormation の記述が何を指しているのかを理解していくうちに、AppSync の仕組みも理解できますので、どうぞお付き合いください。
※サンプルコードのコメントで required と記載のある部分は必須項目です。
このリソースでは API キャッシュの設定を行います。
Resources:
ApiCache:
Type: AWS::AppSync::ApiCache
Properties:
ApiCachingBehavior: PER_RESOLVER_CACHING #required
ApiId: !GetAtt GraphQLApi.ApiId #required
AtRestEncryptionEnabled: false
TransitEncryptionEnabled: false
Ttl: 60 #required
Type: SMALL #required
API キャッシュの設定を行うところになりますので、パラメータ「ApiCachingBehavior」で、FULL_REQUEST_CACHING または PER_RESOLVER_CACHING のどちらかを選択します。前者は名前通りすべてをキャッシュするもので、後者は指定したリゾルバーをキャッシュします。
暗号化は「EncryptoEnabled」と記載のあるパラメータで、インスタンスタイプはパラメータ「Type」で指定することができます。
このリソースでは API キーの作成を行います。
Resources:
ApiKey:
Type: AWS::AppSync::ApiKey
Properties:
ApiId: AppSyncDemoKey #required
Description: This is demo.
Expires: 1617148800
API キーを作成するだけの記述なので、特別なことは何もしません。
注意点としては、パラメータ「Expires」の設定です。ここでは API キーの有効期間を設定できるのですが、デフォルトだと7日となりますので、要件に合わせて調整してください。最小 1 日間~最大 365 日間( UNIX 秒)まで設定可能です。
このリソースではデータソースの作成を行います。
Resources:
DataSource:
Type: AWS::AppSync::DataSource
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
Description: This is demo.
DynamoDBConfig:
AwsRegion: ap-northeast-1
TableName: AppSyncDemoTable
Name: AppSyncDemoDataSource #required
Type: AMAZON_DYNAMODB #required
ServiceRoleArn: DYNAMODB_ROLE_ARN
パラメータ「TYPE」で指定した型に基づいて記述します。データソースの型には、DynamoDB、Lambda、ElasticSearch などがあります。サンプルコードでは DynamoDB を使用しているため、パラメータ「DynamoDBConfig」を用いています。
このリソースではパイプラインリゾルバーを設定します。
Resources:
FunctionConfiguration:
Type: AWS::AppSync::FunctionConfiguration
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
DataSourceName: !GetAtt DataSource.Name #required
Name: AppSyncDemoFuncConf #required
Description: This is demo.
FunctionVersion: '2018-05-29' #required
RequestMappingTemplate: |
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($ctx.args.id),
}
}
ResponseMappingTemplate: |
$util.toJson($context.result)
対象のデータソースを選択し、リクエストとレスポンスマッピングテンプレートを記述します。こちらのリソースはパイプラインリゾルバーを利用しない場合は不要となります。
このリソースでは GraphQL API の作成を行います。
Resources:
GraphQLApi:
Type: AWS::AppSync::GraphQLApi
Properties:
AuthenticationType: API_KEY #required
Name: AppSyncDemo #required
XrayEnabled: false
記述のポイントは、パラメータ「AuthenticationType」を正しく記述するところになります。指定できる API_KEY、AWS_IAM、AMAZON_COGNITO_USER_POOLS、OPENID_CONNECT となっておりますので、要件に合わせて設定してください。
サンプルコードでは、API_KEY を指定しておりますが、ほかのものを設定すると別途パラメータが必要となります。ここでは例として Cognito を利用する場合を記述します。
Resources:
GraphQLApi:
Type: AWS::AppSync::GraphQLApi
Properties:
AuthenticationType: AMAZON_COGNITO_USER_POOLS
UserPoolConfig:
UserPoolId: !Ref UserPool
AwsRegion: ap-northeast-1
DefaultAction: DENY
タイプを変更し、パラメータ「UserPoolConfig」を加えました。この通り指定するタイプによって必要なパラメータが変化しますのでご注意ください。
このリソースではスキーマの作成を行います。
Resources:
GraphQLSchema:
Type: AWS::AppSync::GraphQLSchema
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
Definition: |
schema {
query: Query
mutation: Mutation
}
# Your Schema
こちらはシンプルに、パラメータ「Definition」にスキーマ定義を記述するのみとなります。S3 を利用される方は、パラメータ「DefinitionS3Location」を使用します。
このリソースではリゾルバーの設定を行います。
Resources:
Resolver:
Type: AWS::AppSync::Resolver
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
DataSourceName: !GetAtt DataSource.Name
TypeName: "Mutation" #required
FieldName: "createEvent" #required
Kind: UNIT
RequestMappingTemplate: |
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
"id": $util.dynamodb.toDynamoDBJson($ctx.args.input.id),
},
"attributeValues": $util.dynamodb.toMapValuesJson($ctx.args.input)
}
ResponseMappingTemplate: |
$util.toJson($context.result)
CachingConfig:
CachingKeys:
- $context.arguments.id
Ttl: 60
リゾルバーの設定ではフィールド名を指定して、リクエストとレスポンスマッピングテンプレートを記述します。
パイプラインリゾルバーを利用する場合は、パラメータ「Kind」にて UNIT ではなく、PIPELINE を指定します。加えてパラメータ「PipelineConfig」を記述することで、以下のように設定が可能です。
Resources:
Resolver:
Type: AWS::AppSync::Resolver
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
DataSourceName: !GetAtt DataSource.Name
TypeName: "Mutation" #required
FieldName: "createEvent" #required
Kind: PIPELINE
RequestMappingTemplate: |
{}
ResponseMappingTemplate: |
$util.toJson($context.result)
PipelineConfig:
Functions:
- !GetAtt FunctionConfiguration.FunctionId
FunctionConfiguration のリソースを CloudFormation で記述することを忘れないようにしましょう。パラメータ「PipelineConfig」で必要となります。
それではこれまでに紹介したリソースタイプすべてを使って CloudFormation で AppSync のリソースをデプロイしてみます。
Resources:
ApiCache:
Type: AWS::AppSync::ApiCache
Properties:
ApiCachingBehavior: PER_RESOLVER_CACHING #required
ApiId: !GetAtt GraphQLApi.ApiId #required
Ttl: 60 #required
Type: SMALL #required
ApiKey:
Type: AWS::AppSync::ApiKey
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
Expires: 1617148800
DataSource1:
Type: AWS::AppSync::DataSource
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
Name: AppSyncDemoDataSource1 #required
Type: AMAZON_DYNAMODB #required
ServiceRoleArn: !GetAtt DynamoDBRole.Arn
DynamoDBConfig:
AwsRegion: ap-northeast-1
TableName: !Ref DynamoDBTable1
DataSource2:
Type: AWS::AppSync::DataSource
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
Name: AppSyncDemoDataSource2 #required
Type: AMAZON_DYNAMODB #required
ServiceRoleArn: !GetAtt DynamoDBRole.Arn
DynamoDBConfig:
AwsRegion: ap-northeast-1
TableName: !Ref DynamoDBTable2
FunctionConfigurationStep1:
Type: AWS::AppSync::FunctionConfiguration
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
DataSourceName: !GetAtt DataSource1.Name #required
Description: This is demo.
FunctionVersion: '2018-05-29' #required
Name: AppSyncDemoFuncConf1 #required
RequestMappingTemplate: |
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($ctx.args.id),
}
}
ResponseMappingTemplate: |
$util.toJson($context.result)
FunctionConfigurationStep2:
Type: AWS::AppSync::FunctionConfiguration
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
DataSourceName: !GetAtt DataSource2.Name #required
Description: This is demo.
FunctionVersion: '2018-05-29' #required
Name: AppSyncDemoFuncConf2 #required
RequestMappingTemplate: |
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($ctx.prev.result.groupId),
}
}
ResponseMappingTemplate: |
#if($ctx.error)
$util.error($ctx.error.message, $ctx.error.type)
#end
$util.qr($ctx.prev.result.put("groupName", $ctx.result.groupName))
$util.toJson($ctx.prev.result)
GraphQLApi:
Type: AWS::AppSync::GraphQLApi
Properties:
AuthenticationType: API_KEY #required
Name: AppSyncDemo #required
GraphQLSchema:
Type: AWS::AppSync::GraphQLSchema
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
Definition: |
input CreateInputGroup {
id: String!
groupName: String!
}
input CreateInputUser {
id: String!
name: String!
groupId: String!
}
type Mutation {
createUser(input: CreateInputUser!): Test
createGroup(input: CreateInputGroup!): Test
}
type Query {
getUser(id: ID!): Test
getUserAndGroup(id: ID!): Test
}
type Test {
id: ID!
name: String!
groupId: String!
groupName: String
}
schema {
query: Query
mutation: Mutation
}
Resolver1:
Type: AWS::AppSync::Resolver
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
DataSourceName: !GetAtt DataSource1.Name
TypeName: "Mutation" #required
FieldName: "createUser" #required
Kind: UNIT
RequestMappingTemplate: |
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
"id": $util.dynamodb.toDynamoDBJson($ctx.args.input.id),
},
"attributeValues": $util.dynamodb.toMapValuesJson($ctx.args.input)
}
ResponseMappingTemplate: |
$util.toJson($ctx.result)
Resolver2:
Type: AWS::AppSync::Resolver
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
DataSourceName: !GetAtt DataSource2.Name
TypeName: "Mutation" #required
FieldName: "createGroup" #required
Kind: UNIT
RequestMappingTemplate: |
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
"id": $util.dynamodb.toDynamoDBJson($ctx.args.input.id),
},
"attributeValues": $util.dynamodb.toMapValuesJson($ctx.args.input)
}
ResponseMappingTemplate: |
$util.toJson($ctx.result)
Resolver3:
Type: AWS::AppSync::Resolver
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
DataSourceName: !GetAtt DataSource1.Name
TypeName: "Query" #required
FieldName: "getUser" #required
Kind: UNIT
RequestMappingTemplate: |
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($ctx.args.id),
}
}
ResponseMappingTemplate: |
$util.toJson($context.result)
CachingConfig:
CachingKeys:
- $context.arguments.id
Ttl: 60
PipelineResolver:
Type: AWS::AppSync::Resolver
Properties:
ApiId: !GetAtt GraphQLApi.ApiId #required
TypeName: "Query" #required
FieldName: "getUserAndGroup" #required
Kind: PIPELINE
PipelineConfig:
Functions:
- !GetAtt FunctionConfigurationStep1.FunctionId
- !GetAtt FunctionConfigurationStep2.FunctionId
RequestMappingTemplate: |
{}
ResponseMappingTemplate: |
$util.toJson($context.result)
DynamoDBTable1:
Type: AWS::DynamoDB::Table
Properties:
TableName: AppSyncDemoUserTable
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
DynamoDBTable2:
Type: AWS::DynamoDB::Table
Properties:
TableName: AppSyncDemoGroupTable
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
DynamoDBRole:
Type: AWS::IAM::Role
Properties:
RoleName: AppSyncDemoDynamoDBRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- sts:AssumeRole
Principal:
Service:
- appsync.amazonaws.com
Path: '/'
Policies:
- PolicyName: DynamoDBRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:*
Resource: '*'
上記のCloudFormation スタックテンプレートは実際にデプロイすることが可能です。ユーザーやグループを作成したりユーザー情報を取得してみたりして、遊んでみてください。AppSync 以外には、データソースとして必要なDynamoDB、AppSync とデータソースが連携するのに必要な IAM ロールを作成するテンプレートも記載しております。ぜひ参考にしてください。
今回は7つのリソースタイプを説明していきました。CloudFormation の記述を追っていくごとに AppSync の仕組みが見えてきましたでしょうか?
AWS のコンソール画面と CloudFormation のテンプレートを見比べながら記述しているとより理解が深まりますので、ぜひ試してみてください。
このブログでは、GraphQL や GraphQL のマネージドサービスである AWS AppSync の記事をどんどん公開しておりますので、ご興味のある方はほかの記事もご覧いただければと思います。
AppSync に関する開発は、お気軽にお問い合わせください。
スモールスタート開発支援、サーバーレス・NoSQLのことなら
ラーゲイトまでご相談ください
低コスト、サーバーレスの
モダナイズ開発をご検討なら
下請け対応可能
Sler企業様からの依頼も歓迎