Resources: NotesTable: Type: AWS::Serverless::SimpleTable Properties: PrimaryKey: Name: NoteId Type: String DynamoDBRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - sts:AssumeRole Principal: Service: - appsync.amazonaws.com AppSyncApi: Type: AWS::AppSync::GraphQLApi Properties: AuthenticationType: API_KEY Name: AppSyncApi ApiKey: Type: AWS::AppSync::ApiKey Properties: ApiId: !GetAtt AppSyncApi.ApiId ApiSchema: Type: AWS::AppSync::GraphQLSchema Properties: ApiId: !GetAtt AppSyncApi.ApiId Definition: | type Note { NoteId: ID! title: String content: String } type Query { getNote(NoteId: ID!): Note } type Mutation { saveNote(NoteId: ID!, title: String!, content: String!): Note! } schema { query: Query mutation: Mutation } NotesTableDataSource: Type: AWS::AppSync::DataSource Properties: ApiId: !GetAtt AppSyncApi.ApiId Name: NotesTableDataSource Type: AMAZON_DYNAMODB ServiceRoleArn: !GetAtt DynamoDBRole.Arn DynamoDBConfig: TableName: !Ref NotesTable AwsRegion: !Sub ${AWS::Region} GetNoteResolver: Type: AWS::AppSync::Resolver DependsOn: ApiSchema Properties: ApiId: !GetAtt AppSyncApi.ApiId DataSourceName: !GetAtt NotesTableDataSource.Name TypeName: Query FieldName: getNote RequestMappingTemplate: | { "version": "2017-02-28", "operation": "GetItem", "key": { "NoteId": $util.dynamodb.toDynamoDBJson($context.arguments.NoteId) } } ResponseMappingTemplate: $util.toJson($context.result) SaveNoteResolver: Type: AWS::AppSync::Resolver DependsOn: ApiSchema Properties: ApiId: !GetAtt AppSyncApi.ApiId TypeName: Mutation FieldName: saveNote DataSourceName: !GetAtt NotesTableDataSource.Name RequestMappingTemplate: | { "version": "2017-02-28", "operation": "PutItem", "key": { "NoteId": $util.dynamodb.toDynamoDBJson($context.arguments.NoteId) }, "attributeValues": { "title": $util.dynamodb.toDynamoDBJson($context.arguments.title), "content": $util.dynamodb.toDynamoDBJson($context.arguments.content) } } ResponseMappingTemplate: $util.toJson($context.result) DataSourceToTableConnector: Type: AWS::Serverless::Connector Properties: Source: Id: NotesTableDataSource Destination: Id: NotesTable Permissions: - Read - Write TriggerFunction: Type: AWS::Serverless::Function Properties: Environment: Variables: API_KEY: !GetAtt ApiKey.ApiKey GRAPHQL_URL: !GetAtt AppSyncApi.GraphQLUrl Runtime: nodejs14.x Handler: index.handler InlineCode: | const https = require("https"); exports.handler = async (_) => { const queries = { getNote: /* GraphQL */ ` query { getNote(NoteId: "1") { title content } } `, saveNote: /* GraphQL */ ` mutation { saveNote(content: "some note", NoteId: "1", title: "1st note") { title content } } `, }; const fetch = async (url, options) => new Promise((resolve, reject) => { const req = https.request(url, options, (res) => { const body = []; res.on("data", (chunk) => body.push(chunk)); res.on("end", () => { const resString = Buffer.concat(body).toString(); resolve(resString); }); }); req.on("error", (err) => { reject(err); }); req.on("timeout", () => { req.destroy(); reject(new Error("Request time out")); }); req.write(options.body); req.end(); }); const makeRequest = async (queryName) => { const options = { method: "POST", headers: { "x-api-key": process.env.API_KEY, }, body: JSON.stringify({ query: queries[queryName] }), timeout: 10000, // ms }; const response = await fetch(process.env.GRAPHQL_URL, options); let body = JSON.parse(response); const data = body.data?.[queryName]; if (body.errors !== undefined) { throw JSON.stringify(body.errors); } if (data?.title !== "1st note" || data?.content !== "some note") { throw new Error( `${queryName} error: '${data?.title}' must be '1st note', '${data?.content}' must be 'some note'`); } return body.data; }; const saveResponse = await makeRequest("saveNote"); const getResponse = await makeRequest("getNote"); return { ...saveResponse, ...getResponse }; }; Metadata: SamTransformTest: true