Deploy AppSync GraphQL API with SAM | part two

Stefano Monti
AWS Serverless World
6 min readJan 3, 2024

This post is the sequel of part one about how to deploy AppSync GraphQL API with SAM.

Let’s jump suddenly into the code; in the first part, I talked about the basic AppSync resources and the simple GraphQL schema.
Here, I want to continue to explain the remaining resources to complete the application.
Okay, let’s get started.

Code Base

Resources

TicketTable:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST

The provided CloudFormation template defines an AWS DynamoDB table named TicketTable. This will be our unique data source in this example. Let's break down the key components:

Type: AWS::DynamoDB::Table:
Specifies the resource type, indicating that an AWS DynamoDB table is being defined.

Properties: Contains the configuration and attributes of the DynamoDB table.

  • AttributeDefinitions: Defines the attributes (columns) of the DynamoDB table.AttributeName: id: Specifies an attribute named id. AttributeType: S: Indicates that the attribute id is of type String (S).
  • KeySchema: Defines the primary key schema for the table.
  • AttributeName: id: Specifies the attribute id as the primary key.
  • KeyType: HASH: Indicates that id is the hash key, determining the table's partition key.
  • BillingMode: PAY_PER_REQUEST: Specifies the billing mode for the table. In this case, it is set to PAY_PER_REQUEST, which means the table uses on-demand capacity, and you pay per request made to the table instead of provisioned capacity.

In summary, the CloudFormation template creates a DynamoDB table named TicketTable with a single attribute (id) and a primary key defined on the id attribute. The table is configured to use on-demand billing, where you pay based on the number of read and write requests performed rather than provisioning capacity in advance.

  TicketTableDataSource:
Type: AWS::AppSync::DataSource
Properties:
ApiId: !GetAtt AppSyncTicketAPI.ApiId
Name: TicketTableDataSource
Type: AMAZON_DYNAMODB
ServiceRoleArn: !GetAtt AppSyncDataSourceRole.Arn
DynamoDBConfig:
TableName: !Ref TicketTable
AwsRegion: !Ref AWS::Region


AppSyncDataSourceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service: appsync.amazonaws.com
Policies:
- PolicyName: DataSourceDynamoPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- dynamodb:*
Resource:
- !GetAtt TicketTable.Arn

An AWS AppSync DynamoDB data source (TicketTableDataSource) and related IAM role (AppSyncDataSourceRole) are defined in the given CloudFormation template. Let’s examine each section in detail:

Type: AWS::AppSync::DataSource: Specifies that an AWS AppSync data source is being defined.

Properties: Contains the configuration details for the data source.

  • ApiId: !GetAtt AppSyncTicketAPI.ApiId: Associates the data source with the specified AppSync API (retrieved using !GetAtt).
  • Name: TicketTableDataSource: Sets the name for the data source to “TicketTableDataSource”.
  • Type: AMAZON_DYNAMODB: Specifies that the data source type is Amazon DynamoDB.
  • ServiceRoleArn: !GetAtt AppSyncDataSourceRole.Arn: Associates the data source with the IAM role (AppSyncDataSourceRole) by using its Amazon Resource Name (ARN).
  • DynamoDBConfig: Configures the DynamoDB-specific settings.
  • TableName: !Ref TicketTable: Specifies the name of the DynamoDB table (TicketTable) used as the data source.
  • AwsRegion: !Ref AWS::Region: Specifies the AWS region where the DynamoDB table is located.

Type: AWS::IAM::Role: Specifies that an IAM role is being defined.
The policy named DataSourceDynamoPolicy allows all DynamoDB actions (dynamodb:*) for the specified resource, which is the Amazon Resource Name (ARN) of the DynamoDB table referred to as TicketTable. This policy grants broad permissions to perform any DynamoDB operation on the specified table, essentially providing full access to read, write, and modify data in that DynamoDB table.

In summary, this CloudFormation template creates an AppSync data source connected to a DynamoDB table (TicketTable) and associates it with an IAM role (AppSyncDataSourceRole) that grants permissions for DynamoDB actions on that specific table.

Finally, we can find the three resolvers

  GetSingleTicketResolver:
Type: AWS::AppSync::Resolver
Properties:
ApiId: !GetAtt AppSyncTicketAPI.ApiId
CodeS3Location: ./src/resolvers/getSingleTicket.js
FieldName: getSingleTicket
TypeName: Query
DataSourceName: !GetAtt TicketTableDataSource.Name
Runtime:
Name: APPSYNC_JS
RuntimeVersion: 1.0.0


GetAllTicketsResolver:
Type: AWS::AppSync::Resolver
Properties:
ApiId: !GetAtt AppSyncTicketAPI.ApiId
CodeS3Location: ./src/resolvers/getAllTickets.js
FieldName: getAllTickets
TypeName: Query
DataSourceName: !GetAtt TicketTableDataSource.Name
Runtime:
Name: APPSYNC_JS
RuntimeVersion: 1.0.0


CreateSingleTicketResolver:
Type: AWS::AppSync::Resolver
Properties:
ApiId: !GetAtt AppSyncTicketAPI.ApiId
CodeS3Location: ./src/resolvers/createSingleTicket.js
FieldName: createSingleTicket
TypeName: Mutation
DataSourceName: !GetAtt TicketTableDataSource.Name
Runtime:
Name: APPSYNC_JS
RuntimeVersion: 1.0.0

A resolver is a piece of logic that transforms the incoming GraphQL requests into actions against the underlying data source; in our case, the datasource is the Dynamo table defined before.
Every resolver is linked to a specific datasource (DataSourceName) and with a field inside the schema for example the CreateSingleTicketResolver resolver is linked to the field createSingleTicket inside the Mutation type (this is the connection with the schema):

type Mutation {
createSingleTicket(
date: AWSDateTime
band: String
place: String
): Ticket
}

Look at the same trick already explained in part one: thanks to the SAM magic, the resolvers code has been defined in separate files to keep the code clean and easy to read. For more information about how SAM allows you to do it, read part one in the section where is explained the CloudFormation GraphQL schema resource.

In my opinion, this is bad:

 CreateTodoResolver:
Type: AWS::AppSync::Resolver
Properties:
ApiId: !GetAtt AppSyncTicketAPI.ApiId
FieldName: getSingleTicket
TypeName: Query
DataSourceName: !GetAtt TicketTableDataSource.Name
Runtime:
Name: APPSYNC_JS
RuntimeVersion: 1.0.0
Code: |
import { util } from '@aws-appsync/utils';

export function request(ctx) {
const { id } = ctx.args;
return dynamoDBGetItemRequest({ id });
}

export function response(ctx) {
ctx.stash.parent = ctx.result;
return ctx.result;
}

function dynamoDBGetItemRequest(key) {
return {
operation: 'GetItem',
key: util.dynamodb.toMapValues(key),
};
}

This post is focused on the CloudFormation part, if you are looking for more information about how an AppSync resolver works, take a look at this page:
https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html

Perfect, now you should know all the components of the code base, let’s test our application!

Deploy

Running an AWS SAM (Serverless Application Model) application involves several steps. SAM provides a set of command-line interfaces (CLI) to help you deploy, manage, and test your serverless applications. Below are the general steps to run an AWS SAM application:

Prerequisites:

  1. Install AWS CLI: Make sure you have the AWS CLI installed on your machine. If you want more details, check this out: https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html
  2. Install SAM CLI:
  3. Install the AWS SAM CLI on your machine. You can download it from here.

Steps to Run an AWS SAM Application:

  1. Navigate to the SAM Project: open a terminal and navigate to the root directory of your SAM project.
  2. Build the SAM Application: sam build . This command compiles your application code, fetches dependencies, and creates a deployment package in the .aws-sam directory.
  3. Deploy the SAM Application: sam deploy --profile <YOUR PROFILE NAME>. This command will use the configuration already provided inside the samconfig.toml file.
  4. Cleanup (Optional): sam delete. This will remove the application from the AWS cloud

These steps provide a basic workflow for deploying and testing an AWS SAM application. The specifics may vary depending on your application’s structure and requirements. Adjust the commands and parameters based on your use case and configuration.

Test the application

Go to your AWS console and search ‘AppSync’

You should find an API called ‘Ticket API’

In the ‘Query’ section inside the ‘Ticket API’ you can test the application

That’s all for now, stay tuned for the next steps inside the AppSync world!
Bye
🤗

--

--