Set up CI/CD for AWS AppSync GraphQL API updates - AWS Prescriptive Guidance

Set up CI/CD for AWS AppSync GraphQL API updates

Created by Apoorva Kulkarni (AWS)

Environment: PoC or pilot

Technologies: Modernization; Cloud-native; Software development & testing; Serverless; DevOps

Workload: Open-source

AWS services: AWS AppSync; AWS CodeBuild; AWS CodePipeline; AWS CloudFormation

Summary

Continuous integration and continuous delivery (CI/CD) are critical to recognizing the value of modern application development. Amazon Web Services (AWS) provides multiple services and open-source frameworks that help developers set up a CI/CD pipeline quickly. By automating build, testing and deployment, developers can focus on rapidly delivering new functionality instead of on maintaining and securing CI servers, manually testing their applications, and performing any error-prone deployments of the application stack due to a missed step.

This pattern demonstrates how to apply CI/CD best practices to the development, testing, and deployment of the AWS AppSync (GraphQL) backend API. The pattern builds on the AWS Blog post Building Scalable GraphQL APIs on AWS with CDK, TypeScript, AWS AppSync, Amazon DynamoDB, and AWS Lambda. The pattern sets up a CI/CD pipeline for deploying GraphQL API updates to AWS AppSync, a fully managed GraphQL API service. The pattern uses the AWS Cloud Development Kit (AWS CDK) pipelines module to provision a CI/CD pipeline. AWS CodePipeline orchestrates the building and testing of source code using AWS CodeBuild and the deployment of AWS resources using AWS CloudFormation stacks that are synthesized as a build artifact of the AWS CDK code.

Prerequisites and limitations

Prerequisites

  • An active AWS account

Package versions

The source code (attached) has been tested with the following package versions in the development environment:

  • AWS CDK 1.82.0

  • Node.js 15.5.0

  • npm 6.14.10

  • TypeScript 3.9.7

For additional dependencies and libraries used, see package.json in the attached source code. Those dependencies and libraries are installed as a part of setting up your development environment as described in the Epics section.

Architecture

Target technology stack  

Application resources

  • AWS AppSync GraphQL API, GraphQL schema, resolvers, API key, data source

  • AWS CloudFormation stack

  • Amazon DynamoDB table

  • AWS Identity and Access Management (IAM) roles and policies

  • AWS Lambda function

Pipeline resources

  • AWS CloudFormation stack

  • AWS CodeBuild projects

  • AWS CodePipeline pipeline, webhook

  • IAM roles and policies

  • AWS Key Management Service (AWS KMS) key and alias

  • AWS Secrets Manager

  • Amazon Simple Storage Service (Amazon S3) bucket

Target architecture 

The following diagram shows details of the stack update architecture.

Automation and scaling

To add target environments for deployment of the application stack in different accounts and Regions, use the pipeline.addApplicationStage() API of the AWS CDK pipeline module. For more information about cross-account deployments, see the documentation.

Tools

Tools

  • AWS AppSync – AWS AppSync provides a robust, scalable GraphQL interface for application developers to combine data from multiple sources, including Amazon DynamoDB and AWS Lambda.

  • AWS CLI – AWS Command Line Interface (AWS CLI) is a unified tool to manage your AWS services.

  • AWS Cloud Development Kit – The AWS Cloud Development Kit (AWS CDK) is a software development framework for defining cloud infrastructure in code and provisioning it through AWS CloudFormation.

  • AWS CloudFormation – AWS CloudFormation is a service that helps you model and set up your Amazon Web Services resources.

  • AWS CodeBuild – AWS CodeBuild is a fully managed build service in the cloud. CodeBuild compiles your source code, runs unit tests, and produces artifacts that are ready to deploy.

  • AWS CodePipeline – AWS CodePipeline is a continuous delivery service you can use to model, visualize, and automate the steps required to release your software.

  • Amazon DynamoDB – Amazon DynamoDB is a fully managed NoSQL database service that provides fast and predictable performance with seamless scalability.

  • AWS Lambda – AWS Lambda supports running code without provisioning or managing servers.

  • Node.js runtime – Node.js is an event-driven JavaScript runtime environment designed for building scalable network applications.

  • Git client – A Git client is a command line or desktop tool for checking out the required artifacts from a Git repository.

Code

The source code is attached as a .zip file.

Epics

TaskDescriptionSkills required
Set up the workstation.

Install the Node.js runtime, AWS CDK, Git, and TypeScript.

Developer
Install the AWS CDK.

To set up a development environment for the AWS CDK, follow the instructions in the AWS CDK documentation.

Developer
Create a GitHub repository for the source code.

Create a new GitHub repo called cdk-graphql-backend.

Developer
Push the code.

Download the attached .zip file. In the project directory, set up the GitHub repository as origin, commit the changes, and push them to the origin. 

cd cdk-graphql-backend git init --initial-branch=main git add . git commit -m 'initial commit' git remote add origin https://github.com/<GitHub Org>/cdk-graphql-backend.git git push origin main

Developer
Install dependencies.

To install all the dependencies of the reference example as defined in package.json, run the npm install command.

npm install npm run build

Developer
Set up the AWS CLI.

Set up the AWS CLI. Use profiles or environment variables so that you are able to issue AWS CLI commands against your AWS account. For more information, see the AWS documentation.

Developer
Create credentials.

Obtain GitHub token, and create an AWS Secrets Manager secret to use for CodePipeline integration.

aws secretsmanager create-secret \ --name GITHUB_TOKEN \ --description "Github Token" \ --secret-string "<Insert Github Oauth Token>"

Developer
Bootstrap the AWS CDK.

To bootstrap the AWS CDK, use the CDK_NEW_BOOTSTRAP flag.

env CDK_NEW_BOOTSTRAP=1  cdk bootstrap \  --cloudformation-execution-policies \  arn:aws:iam::aws:policy/AdministratorAccess \  aws://<AWS ACCOUNT ID>/us-west-2

Developer
TaskDescriptionSkills required
Create the GraphQL schema.

For information on creating the GraphQL schema, see the AWS documentation.

Developer
Create AWS AppSync GraphQL API.

Create an AWS AppSync API backend by using AWS CDK code, as shown in the source code.

Developer
Create the Lambda data source.

Develop a Lambda function to serve as the data source for the AWS AppSync resolvers for the queries and mutations.

Developer
Create the AWS Appsync resolvers.

To route the queries and mutations to the appropriate data source, create resolvers in AWS AppSync.

Developer
Create the data stores.

Create data stores, such as DynamoDB tables, for your GraphQL API.

Developer
TaskDescriptionSkills required
Create the Source stage.

Set up the source stage so that commits can activate the pipeline.

Developer
Create the Build stage.

Set up the Build stage to build the AWS CDK source code. In addition, build any Lambda code that is provided as the data source for the AWS AppSync API.

Developer
Create the Unit Tests stage.

Create unit tests to test the synthesized CloudFormation stacks. Include application unit tests for Lambda functions, GraphQL schema validation, and so forth.

Developer
Create the Alpha Deployment stage.

Create a stage to deploy the application stack to an Alpha environment for further testing and validations.

Developer
Create the End-to-End Test stage.

Create end-to-end tests to validate the AWS AppSync GraphQL API endpoint returns appropriate results for queries and mutations.

Developer
Create the Production Deployment stage.

Create a stage to deploy the application stack to a production environment for end users.

To deploy the pipeline stack, run the following command.

cdk deploy --parameters GitHubOrg=<GitHub Org>

Developer

Additional information

Testing

Unit testing

The example shows how to perform unit testing of the application's synthesized CloudFormation stack by using the Jest library's snapshot testing capabilities. A snapshot test case renders a stack, takes a snapshot, then compares it to a reference snapshot file stored alongside the test. If the two snapshots do not match, the test will fail. Snapshot mismatches can occur either because the change is unexpected or because the reference snapshot must be updated to the new version of the stack.

test('Snapshot test - AppsyncCdkApp', () => { const stack = new Stack(); // WHEN new AppSyncCdkApp.AppsyncCdkAppStack(stack, 'MyTestConstruct'); // THEN expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot(); });

Updating tests

To update the unit tests when adding test cases or making changes to the AWS CDK code of the application stack, first update snapshot files. To update the snapshot files, run the following command.

$ npm test -- -u --group=unit 

End-to-end testing

Testing your AWS AppSync GraphQL API backend through its API interface gives you the most confidence to determine whether your API is working as expected for your customers. The following example shows how to use the Amplify JavaScript library combined with the Jest snapshot testing described in the Unit testing section. You can use this approach to perform end-to-end tests that mimic an API client performing operations against the Alpha environment.

import Amplify, { API } from 'aws-amplify'; Amplify.configure({ aws_appsync_region: process.env.AWS_DEFAULT_REGION, // Stack region aws_appsync_graphqlEndpoint: process.env.API_URL, // AWS AppSync endpoint aws_appsync_authenticationType: "API_KEY", //Primary AWS AppSync authentication type aws_appsync_apiKey: process.env.API_KEY // AppSync API Key }); describe('List Empty Notes', () => { it('List Notes, should be empty', async () => { const query = ` query listNotes { listNotes { id name completed } } ` const response = await API.graphql({ query }); expect(response).toMatchSnapshot(); }); });

Updating Tests

To update either the end-to-end tests when updating the graphql schema or making other changes, run the following command.

$ npm test -- -u --group=e2e

Pipeline stages

After the pipeline has been deployed successfully, further changes to the application code or the pipeline can be deployed by pushing commits to GitHub. The following sections describe what the different stages in the pipeline do.

Source 

Creates a webhook for integrating with GitHub so that any commit to the main branch initiates the pipeline process.

Build 

Creates a CodeBuild project to build the source code. The AWS CDK pipelines module uses this stage to synthesize CloudFormation stacks. Additionally, in this pattern, a TypeScript Lambda function, which is included in the application source code, is also compiled.

UpdatePipeline (self-mutate)

Applies any changes to the pipeline itself through self-mutation using a CloudFormation change set. For more information, see the AWS CDK pipeline module documentation.

Assets 

Creates a CodeBuild project to prepare and publish AWS CDK assets. For more information, see the AWS CDK pipeline module documentation.

UnitTests 

Creates a CodeBuild project to run any unit tests that exist in the source code. In addition, you can use this stage to validate the graphql schema using graphql-schema-utilities, an open-source package for validating and merging graphql schemas.

DeployAlpha 

Uses a CloudFormation change set to deploy the application stack that provisions application resources, such as AWS AppSync, DynamoDB tables, and Lambda functions, to an Alpha environment where you can run integration tests, end-to-end tests, and so forth.

E2ETesting 

Creates a CodeBuild project to perform end-to-end testing against the Alpha environment.

DeployProd 

Uses a CloudFormation change set to deploy the application stack that provisions application resources to the production environment.

Attachments

To access additional content that is associated with this document, unzip the following file: attachment.zip