Home>>Tech>>Getting started with Chalice to create AWS Lambdas in Python – Step by Step Tutorial
Tech

Getting started with Chalice to create AWS Lambdas in Python – Step by Step Tutorial

If you’re into serverless stuff, you already know what is AWS Lambda. But if you don’t know, AWS Lambda is a serverless service provided by Amazon where you can create ‘functions’ and deploy them in AWS, which you can run without having any server instances (such as EC2). Hence the name serverless. You can then trigger these functions using a variety of built in triggers such as S3 events, CloudWatch rules, API Gateways, and much more.

AWS Lambda supports only a handful of programming languages such as NodeJS, Java, Python, and others. If you’re writing your Lambda function in Python, you can use Chalice to make life a bit easier. Using Chalice, you can write a Lambda function, test it locally, and even deploy the Lambda function to your development, test, or production environments. In this post, we’ll see how we can install Chalice on our local machines, write a simple REST API to return the famous “Hello, world!” response, and deploy it to a dev stage on AWS Lambda. This deployment will automatically create an API Gateway service in AWS which will expose our Lambda function to the world with a secure HTTPS endpoint. So let’s get started.

Install Chalice

To install Chalice, you first need to have Python and pip installed on your machine. We’ll assume that you have those things installed for now. The next step is to install Chalice, which is very simple actually. Just install it using pip or pip3 with the appropriate command below:

pip install chalice

If you are using Python 3.x with pip3, you can use the following command to install Chalice:

pip3 install chalice

One thing you need to make sure is that you’re using Python 2.7, Python 3.6, or Python 3.7 on your local machine. This is because as of writing this post, Amazon only support these three versions of Python for Lambdas. So even Chalice supports only these three versions. So make sure of that.

Now that you have Chalice installed on your machine, we’ll go ahead and setup AWS credentials on your local machine so that Chalice can deploy your functions on Lambda and also create API Gateways for those functions.

Setting up AWS Credentials

If you already have aws-cli setup on your local machine, you probably have already configured AWS credentials. In that case, you can skip this step and move to the next section.

There are many ways in which you can setup AWS credentials on your local machine. You can check AWS docs for more info on that. But for this tutorial, we’ll go with the most easiest way, creating an environment file and saving the credentials in that.

For this, we first need to create a .aws directory in your home directory. This directory will house all the config we need. For this, use the following command in your terminal:

mkdir ~/.aws

Next, cd into this directory and create a file called config inside this directory. You can use any editor of your choice. I’ll use vim as I’m comfortable with that. You can use the following command to change the directory and create the file, and then open up that file for editing:

cd ~/.aws && vim config

Inside this file, we need to set our AWS access key, secret key, and a preferred default region. All the Lambda functions you deploy using Chalice will use these credentials. So be careful with the credentials that you provide here. Now, in the file, paste the following content, and change the values accordingly:

[default]
aws_access_key_id=<your_access_key_here>
aws_secret_access_key=<your_secret_key_here>
region=<your_region_here>

Save this file and exit the editor. You’re done configuring AWS credentials. Let’s move on to creating a new project with Chalice and writing our code.

Creating a new project with Chalice

For this, cd into the directory where you want to save your new project. I’ll use the following command to change the directory to my local code repository:

cd ~/code/python/

Once we’re in the desired directory , we can use the new-project command that Chalice provides to create a new project. I’ll create a new project with name ‘chalice-poc’ using the command below:

chalice new-project chalice-poc

After running that command, list the directories and you should be able to see the new directory created. Now get into that directory:

cd chalice-poc

For the rest of the tutorial, we’ll be in this directory. Now open this directory in an IDE or text editor of you choice. You should see a bunch of files and directories already created for you. I use Sublime Text for all my Python projects. So I’ll run the following command to open the whole directory in the editor:

subl .

Understanding the default folders and files

You can see a folder structure something like the following, which is already created for you.

Chalice project structure

Let’s talk a bit about each of these files briefly:

  • .chalice/config.json – This file will hold all the configuration of your environments used for deploying your Lambda function to AWS. Configuration such as environment variables, the ARN of the user that has to be used to deploy the Lambda function, name of the Lambda function, etc.
  • app.py – This is the main Python file of your Lambda function. The control comes here when your Lambda function is triggered.
  • requirements.txt – This is the file used for dependency management. You specify the name and the version of the dependency you want, and AWS will take care of provisioning it for your Lambda function. But keep in mind, not all Python dependencies are available here. You’ll have to package them yourself if you don’t find it in the registry.

The code

Now that we have that out of our way, let’s open up the app.py file and check what we have. You should find something like the following, depending on the version of Chalice you’re using:

from chalice import Chalice

app = Chalice(app_name='chalice-poc')

@app.route('/')
def index():
    return {'hello': 'world'}

# The view function above will return {"hello": "world"}
# whenever you make an HTTP GET request to '/'.
#
# Here are a few more examples:
#
# @app.route('/hello/{name}')
# def hello_name(name):
#    # '/hello/james' -> {"hello": "james"}
#    return {'hello': name}
#
# @app.route('/users', methods=['POST'])
# def create_user():
#     # This is the JSON body the user sent in their POST request.
#     user_as_json = app.current_request.json_body
#     # We'll echo the json body back to the user in a 'user' key.
#     return {'user': user_as_json}
#
# See the README documentation for more examples.
#

As you can see from the code already provided in the file, we have a pre-built API with the endpoint / which returns a JSON object to the client. We can run just this and it’ll work. You’ll have a working Lambda function locally. But just for the sake of it, let’s change the response of the API. We’ll use a proper Response object with response code and a body.

For this, we need to import the Response object from Chalice. So we’ll change the import statement at the top of the page to this:

from chalice import Chalice, Response

We just added one more class to the import statement. Next, we’ll change the index() method to return a new Response object:

@app.route('/')
def index():
	return Response(status_code=200, body={'hello': 'world'})

We’ll stop the coding at this. You can accept path variables, query parameters, and POST or PUT body here. But to keep things simple, we’ll just go with this GET API. The next part is, running this Lambda function locally.

Running the Lambda function locally

Chalice makes it super easy to run and test Lambda functions locally, as if we had deployed it on our servers. To run the Lambda locally, we just need to run a super simple command in our terminal. I’m assuming here that you’re still in the project directory in your terminal. With that assumption, run the following command in the terminal:

chalice local

Once you run that command, you should get a confirmation that the local server has started and is serving on some port, which is 8000 by default. So you should get the following output:

➜  chalice-poc chalice local
Serving on http://0.0.0.0:8000
Restarting local dev server.

Right, so once you see this message, you can head over to your browser and enter the address localhost:8000, and you should get the response which we have written in the code.

In some cases, you might see an error or waning from Chalice which says that it’s not able to resolve localhost. And in some cases, you might not get any errors or warning, but might not be able to connect to Chalice from your local machine. This a common problem I’ve seen and is very simple to resolve. We’ll use the –host option of the Chalice command to specify the localhost as 0.0.0.0. So your command will now look something like the following, along with the same output:

➜  chalice-poc chalice local --host 0.0.0.0
Serving on http://0.0.0.0:8000
Restarting local dev server.

Configuring Lambda function for deployment

Now that we have the Lambda function up and running locally as expected, we’ll make the necessary configuration so that we can deploy the Lambda function to the AWS cloud.

For this, we’ll head over to the .config directory in the project root and open up the config.json file. You should already have some content similar to the following in the file:

{
  "version": "2.0",
  "app_name": "chalice-poc",
  "stages": {
    "dev": {
      "api_gateway_stage": "api"
    }
  }
}

So Chalice has given us a blueprint for this configuration as well. We’ll just add a few more fields to the “dev” object here. For each stage in your setup, you’ll have an object here. Insides the “stages” object, you can create any number of stages you want with custom names, and Chalice will just follow that instruction. Anyway, let’s make changes to our file so that it looks something like the following:

{
	"version": "2.0",
	"app_name": "chalice-poc",
	"stages": {
		"dev": {
			"api_gateway_stage": "api",
			"manage_iam_role":false,
			"iam_role_arn":"arn:aws:iam::xxxyyyzzz:role/abc",
			"environment_variables": {
				
			}
		}
	},
	"app_name": "chalice-poc-dev"
}

As you can see in the configuration above, we have asked Chalice not to manage IAM roles and we have mentioned the role ARN ourselves. If you are not familiar with all this, you can just set the parameter “manage_iam_role” to true and Chalice will take care of that. I don’t do that because I prefer to create the roles myself and reuse the roles whenever possible. Anyway, we’re now done with the configuration. Let’s deploy.

Deploying the Lambda function to AWS

Deploying to AWS is I guess the most easiest part of this tutorial. It’s just one command and you’re done. When you’re ready to deploy, go back to your AWS credentials configuration and make sure everything is correct.

To deploy your Lambda function to the cloud using Chalice, just run the following command in the terminal from the project root directory:

chalice deploy

Once you run this command, it’ll take a while to finish. You’ll not get any feedback in the terminal during this time. So don’t get scared or worried as to what is happening. Once the process is done, you’ll get the public URL of the API Gateway which is in front of your deployed Lambda function, something like the following:

Creating deployment package.
Updating lambda function: chalice-poc-dev
Updating rest API
Resources deployed:
  - Lambda ARN: arn:aws:lambda:us-east-2:xxxyyyzzzaaa:function: chalice-poc-dev
  - Rest API URL: https://abcdefgh.execute-api.us-east-2.amazonaws.com/api/

You can use that URL to trigger your Lambda function. So open up your browser again and go to the URL that was provided. You should see the response immediately.

You can make a note the URL that’s provided here as the URL for that stage of your Lambda function. But you don’t have to worry if you lose this URL. You can get it back in the API Gateway section in the AWS Console.

So, that’s the end of the tutorial. You can create more routes in the app.py file, add more methods to it and build a proper Lambda function. Please let me know in the comments below if you have any issues with your Lambda or are not able to follow the tutorial. And as usual, if you want the complete project, check it out from my Github repo.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: