AWS Developer Tools Blog

Automatically deploy a Serverless REST API from GitHub with AWS Chalice

AWS Chalice lets you quickly create serverless applications in Python. When you first start using Chalice, you can use the chalice deploy command to deploy your application to AWS without any additional setup or configuration needed other than AWS credentials. As your application grows and you add additional team members to your project, you’ll want a system that can automatically deploy your application instead of remembering to run chalice deploy every time you make a change to your app. One way to do this is use AWS CodeBuild and AWS CodePipeline to build and deploy your application whenever changes are pushed to a Git repository.

You can set this process up by using the AWS Console or by creating an AWS CloudFormation template for your deployment pipeline, but Chalice includes functionality to automatically generate a deployment pipeline template for you. In this post, we’ll show you how to set this up.

Walkthrough

To demonstrate this, we’ll create a Chalice application and configure it to automatically deploy whenever we push our changes to GitHub. To follow along you’ll need:

  • Python 3.7 or higher

  • The AWS CLI installed and configured

  • A GitHub account

First we’ll need to create a new development environment and create a new Chalice application.

$ python3 -m venv /tmp/venv37
$ . /tmp/venv37/bin/activate
$ pip install chalice
$ chalice new-project testpipeline
$ cd testpipeline

Next, we’ll configure a local Git repository for our app.

$ git init .
$ git add -A .
$ git commit -m "Initial commit"
[master (root-commit) c35d315] Initial commit
4 files changed, 40 insertions(+)
create mode 100644 .chalice/config.json
create mode 100644 .gitignore
create mode 100644 app.py
create mode 100644 requirements.txt

Now that we’ve done that, we’ll need to create a GitHub repository for our application. You can go to the Create a New Repository page on GitHub and follow the steps to create a new repository. This can be either a public or private repository. Once you’ve created your repository, you’ll need to add GitHub as a remote for your application.

$ git remote add origin git@github.com:YOUR-NAME/YOUR-PROJECT.git
$ git push origin master

Now that we’ve configured GitHub we can configure our deployment pipeline. Instead of writing this pipeline definition by hand, Chalice includes a generate-pipeline command that can generate a starter template for you. We’ll use this command to create our initial template.

$ mkdir infrastructure
$ chalice generate-pipeline \
--source github \
--buildspec-file buildspec.yml \
--pipeline-version v2 \
infrastructure/pipeline.json

In the command above there’s several arguments we’re providing. The --source github argument is used to configure our pipeline to deploy from a GitHub repository instead of an AWS CodeCommit repository. The --buildspec-file argument is used to specify that we want a buildspec file generated instead of being included inline with our CloudFormation template, and the --pipeline-version specifies that we want to generate a v2 template instead of the default v1 template. The v2 template includes several improvements over the v1 template including using the latest CodeBuild images and the latest Buildspec specification. See the Chalice documentation for more details.

This command will generate two files, a buildspec.yml file and an infrastructure/pipeline.json file. We’ll add these files to our Git repository.

$ git add buildspec.yml infrastructure/pipeline.json
$ git commit -m "Add deployment pipeline template"

We’re almost ready to deploy our pipeline. In order for AWS CodePipeline to retrieve changes from our GitHub repository, we must provide an access token that our pipeline can use. To do this, we’ll create a personal access token on GitHub and store this value in AWS Secrets Manager. Our CloudFormation template will then reference this secret so that we don’t hardcode our access token in our template. You can follow the GitHub documentation on how to generate a personal access token. The AWS Secrets Manager documentation has a tutorial on how to store and retrieve secrets. You can also use the AWS CLI to create a new secret. Create a file named /tmp/secrets.json with the following contents:

{"OAuthToken": "abcdefghhijklmnop"}

Be sure to replace the value with your own personal access token. Next run this command to create a new secret.

$ aws secretsmanager create-secret --name GithubRepoAccess \
--description "Token for Github Repo Access" \
--secret-string file:///tmp/secrets.json

We can now deploy our pipeline. We’ll use the AWS CLI to deploy our CloudFormation template.

$ aws cloudformation deploy --template-file infrastructure/pipeline.json \
--stack-name MyChaliceApp --parameter-overrides \
GithubOwner=repo-owner-name \
GithubRepoName=repo-name \
--capabilities CAPABILITY_IAM

Be sure to replace the GithubOwner and GithubRepoName with your own values.

Once our stack is created, we can go to our the CodePipeline page in the AWS Console and we’ll see that our pipeline was created.

Chalice pipeline created

Our application will take a few minutes to deploy. Once the last stage in our pipeline was finished running we can now test our application.

Chalice pipeline finished

To test our application, we’ll need to retrieve the EndpointURL associated with our application. You can go to the CloudFormation console page and lookup the value of EndpointURL in the stack outputs tabs.

Chalice CloudFormation outputs

Now we can make a GET request to our endpoint URL we’ll see our hello world response:

$ curl -w '\n' https://rest-api-id.execute-api.us-west-2.amazonaws.com/api/
{"hello":"world"}

At this point, we have our deployment pipeline set up. Any changes to our GitHub repository will automatically be deployed. To test this, make a change to your app.py file.

from chalice import Chalice

app = Chalice(app_name='testpipeline')

@app.route('/')
def index():
    return {'hello': 'world, these are new changes!'}

We’ll now commit and push our changes.

$ git add app.py
$ git commit -m "Change hello world message"
[master 68cfc91] Change hello world message
1 file changed, 1 insertion(+), 3 deletions(-)
$ git push origin master

After a few minutes, we can see that application has been deployed.

$ curl -w '\n' https://rest-api-id.execute-api.us-west-2.amazonaws.com/api/
{"hello":"world, these are new changes!"}

Next Steps

Now that we have our deployment pipeline in place, there’s a few things we can do from here.

  • Continue building out our application by modifying our app.py file.

  • Change the buildspec.yml file to modify how our application is built. We can add additional commands to run unit tests, run linters, type checkers, etc before we deploy our application.

  • Modify our infrastructure/pipeline.json file to add new stages to our deployment pipeline. You’ll need to rerun the aws cloudformation deploy command if you make changes to your deployment pipeline.

If you’d like to deep dive on deploying your application with Chalice, our documentation goes into more detail and has additional options for you to consider. Let us know what you think! You can give feedback on our GitHub page.