まず AppSync で "Hello, World!" という文字列を返す単純な GraphQL API を作成し、サービスの利用法をみていきます
まずは GraphQL SDL(Schema Definition Language) を用いて GraphQL API のインターフェースを定義していきます。次のような単純な User データを返却する user クエリを定義します。
schema { query: Query } type Query { user(id: ID!): User } type User { id: ID! name: String! }
ことはじめとして、決まった値を返すようなリゾルバを定義します。
{ "id": 1, "name": "hoge" }
データソースは None タイプを選択したものを指定し、レスポンスマッピングテンプレートにて前述の定数値を返すように設定します。
次のようなクエリを実行します。定数値を返すレスポンスマッピングテンプレートを設定しているので id を変えても常に同じ値が帰ります。name のみにすると、戻り値に id は含まれなくなります。
query { user(id: 1) { id name } }
CloudFormation テンプレートで以上のリソースを表現しておくとわかりやすいかもしれません。次のようになります。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > Hello AppSync Resources: GraphQLApi: Type: AWS::AppSync::GraphQLApi Properties: Name: GraphQLHello AuthenticationType: API_KEY GraphQLSchema: Type: AWS::AppSync::GraphQLSchema Properties: ApiId: !GetAtt GraphQLApi.ApiId DefinitionS3Location: schema.graphql GraphQLNoneDataSource: Type: AWS::AppSync::DataSource Properties: Name: GraphQLNoneDataSource ApiId: !GetAtt GraphQLApi.ApiId Type: NONE GraphQLResolver: Type: AWS::AppSync::Resolver Properties: ApiId: !GetAtt GraphQLApi.ApiId TypeName: Query FieldName: user DataSourceName: !GetAtt GraphQLNoneDataSource.Name RequestMappingTemplate: '{"version": "2017-02-28", "payload": {}}' ResponseMappingTemplate: '{"id":1, "name":"hoge"}' GraphQLAPIKey: Type: AWS::AppSync::ApiKey Properties: ApiId: !GetAtt GraphQLApi.ApiId
定数値をレスポンスマッピングテンプレートから返却するのではなく、Lambda 関数から返してみます。
以下のような単純な Lambda 関数を作成し、これをデータソースとして指定します。
import json def lambda_handler(event, context): print(json.dumps(event, ensure_ascii=False)) return { 'id': event['id'], 'name': 'hogefuga' }
リゾルバのマッピングテンプレートを以下のように設定すると背後にある Lambda 関数をデータソースとして呼び出せます
# request { "version" : "2017-02-28", "operation": "Invoke", "payload": $util.toJson($context.args) } # response $util.toJson($context.result)
以下のようなクエリを実行すると無事 Lambda から返却された id に対応するレスポンスが得られます(name は固定値ですが...)。
query { user(id: 123) { id name } }
あわせて Lambda 関数の CloudWatch Logs をみると以下のようなイベントが渡っていることがわかります
{ 'id': '123' }
Lambda 関数が絡んできたので SAM が生きます。テンプレートは以下のようなもの。AppSync から Lambda を実行する際の実行ロールがやや冗長なので、スマートにかけるようになると便利そうですね。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > Hello AppSync Resources: GraphQLApi: Type: AWS::AppSync::GraphQLApi Properties: Name: GraphQLHello AuthenticationType: API_KEY GraphQLSchema: Type: AWS::AppSync::GraphQLSchema Properties: ApiId: !GetAtt GraphQLApi.ApiId DefinitionS3Location: schema.graphql GraphQLDataSourceLambdaFunction: Type: AWS::Serverless::Function Properties: CodeUri: get_user/ Handler: app.lambda_handler Runtime: python3.8 AppSyncLambdaInvokeRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: appsync.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: AllowInvokeLambda PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: lambda:invokeFunction Resource: !GetAtt GraphQLDataSourceLambdaFunction.Arn GraphQLLambdaDataSource: Type: AWS::AppSync::DataSource Properties: Name: GraphQLLambdaDataSource ApiId: !GetAtt GraphQLApi.ApiId Type: AWS_LAMBDA LambdaConfig: LambdaFunctionArn: !GetAtt GraphQLDataSourceLambdaFunction.Arn ServiceRoleArn: !GetAtt AppSyncLambdaInvokeRole.Arn GraphQLResolver: Type: AWS::AppSync::Resolver Properties: ApiId: !GetAtt GraphQLApi.ApiId TypeName: Query FieldName: user DataSourceName: !GetAtt GraphQLLambdaDataSource.Name RequestMappingTemplate: '{ "version" : "2017-02-28", "operation": "Invoke", "payload": $util.toJson($context.args) }' ResponseMappingTemplate: '$util.toJson($context.result)' GraphQLAPIKey: Type: AWS::AppSync::ApiKey Properties: ApiId: !GetAtt GraphQLApi.ApiId
JSONPlaceholder のエンドポイント: https://jsonplaceholder.typicode.com を指定し、データソースを作成する
リゾルバのマッピングテンプレートを以下のように設定すると背後にある HTTP エンドポイントをデータソースとして呼び出せる
# request {"version":"2018-05-29","method":"GET","resourcePath":"/users/$ctx.args.id"} # response $context.result.body
以下のようなクエリを実行する
query { get(id: "3") { id name } }
すると以下のような結果が得られる
{ "data": { "get": { "id": "3", "name": "Clementine Bauch" } } }
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > Hello AppSync Resources: GraphQLApi: Type: AWS::AppSync::GraphQLApi Properties: Name: GraphQLHello AuthenticationType: API_KEY GraphQLSchema: Type: AWS::AppSync::GraphQLSchema Properties: ApiId: !GetAtt GraphQLApi.ApiId DefinitionS3Location: schema.graphql GraphQLAPIKey: Type: AWS::AppSync::ApiKey Properties: ApiId: !GetAtt GraphQLApi.ApiId GraphQLHTTPDataSource: Type: AWS::AppSync::DataSource Properties: Name: GraphQLHTTPDataSource ApiId: !GetAtt GraphQLApi.ApiId Type: HTTP HttpConfig: Endpoint: https://jsonplaceholder.typicode.com GraphQLResolver: Type: AWS::AppSync::Resolver Properties: ApiId: !GetAtt GraphQLApi.ApiId TypeName: Query FieldName: user DataSourceName: !GetAtt GraphQLHTTPDataSource.Name RequestMappingTemplate: '{"version":"2018-05-29","method":"GET","resourcePath":"/users/$ctx.args.id"}' ResponseMappingTemplate: '$context.result.body'