Skip to content

Instantly share code, notes, and snippets.

@noahcoad
Last active January 24, 2023 05:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save noahcoad/0f0715bdc60e910367e4aa9fdf473be7 to your computer and use it in GitHub Desktop.
Save noahcoad/0f0715bdc60e910367e4aa9fdf473be7 to your computer and use it in GitHub Desktop.
Get Started with AWS Lambdas using AWS Chalice on Mac

Get Started w AWS Lambda
Using AWS Chalice on Mac

AWS Chalice makes creating AWS Lambdas and HTTP APIs very easy. It is a microservice deployment framework, written by AWS for AWS. It's my favorite way to quickly create AWS Lambdas, HTTP APIs, and wire up AWS cloud servics.

Non-Mac Users
These instructions are written assuming you're using a Mac. If you're using another platform, please see this AWS Intro w Python tutorial that is platform independent.

Prereqs

We're assuming you have these:

  • An AWS Account (it's free to get started)
  • Homebrew Installed
  • AWS CLI tool installed: brew install awscli
  • AWS CLI tool configured with your account creds: aws configure
  • jq, python3, and HTTPie installed: brew install jq httpie python3

Start using AWS Lambda w AWS Chalice

Create a new AWS Chalice project.

# lets make a new folder to work in
mkdir -p ~/code/aws
cd ~/code/aws

# installs the AWS Chalice python framework
pip3 install chalice

# creates a new chalice project called 'workshop-intro'
chalice new-project intro

# change into the folder and list files
cd intro
ls

Edit app.py in your favorite editor and replace ALL the code (you can keep the commented out lines in app.py) with...

from chalice import Chalice

app = Chalice(app_name='intro')

@app.lambda_function()
def hello_world(event, context):
    return {'hello': 'world'}

This will end up creating a single AWS Lambda called "intro-dev-hello_world".

Save the file, then back in the terminal...

# deploys the new code to the AWS Lambda cloud
chalice deploy

# call the lambda using AWS cli
aws lambda invoke --function-name intro-dev-hello_world out.json
cat out.json

# or more simply with chalice
chalice invoke -n hello_world

Notice the method above called "hello_world" is deployed as an AWS Lambda function.

View your new lambda on the AWS Console at AWS Lambda Console

Now add another method that uses a parameter by adding these lines to the end of app.py...

@app.lambda_function()
def hello_there_name(event, context):
    name = event['name']
    return {'hello': name}

Save file, then redeploy and run the new lambda with input...

# redeploy the latest updates
chalice deploy

# run the new lambda, and pass in a simple JSON object as input
echo '{"name": "Kyle"}' | chalice invoke -n hello_there_name

Notice you've now created two lambdas (see AWS Lambda Console)

You can also see these lambdas by running...

# use AWS command line tool to list functions
aws lambda list-functions

# a little fancier, use the jq tool to filter to just the function names
aws lambda list-functions | jq '.Functions[].FunctionName'

# and if you already have a lot of lambda functions, may be handy
# to filter the list to just ones that start with this prefix
aws lambda list-functions | jq '.Functions[].FunctionName|select(startswith("intro-dev"))'

Next let's create an HTTP API that will be backed by a Lambda. Add these lines to the end

Finally delete the lambdas so far with...

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

Save file. Deploy again with...

chalice deploy

Notice this time you should get an output that looks like this...

Creating deployment package.
Updating policy for IAM role: intro-dev
Updating lambda function: intro-dev-hello_world
Updating lambda function: intro-dev-hello_there_name
Creating lambda function: intro-dev
Creating Rest API
Resources deployed:
  - Lambda ARN: arn:aws:lambda:us-west-2:642028586177:function:intro-dev-hello_world
  - Lambda ARN: arn:aws:lambda:us-west-2:642028586177:function:intro-dev-hello_there_name
  - Lambda ARN: arn:aws:lambda:us-west-2:642028586177:function:intro-dev
  - Rest API URL: https://08ytd34hwk.execute-api.us-west-2.amazonaws.com/api/

Note the Rest API URL and call it with httpie:

http https://08ytd34hwk.execute-api.us-west-2.amazonaws.com/api/ 

You should get some output like this...

➜  http https://08ytd34hwk.execute-api.us-west-2.amazonaws.com/api/
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 17
Content-Type: application/json
Date: Sun, 16 Feb 2020 23:54:33 GMT
Via: 1.1 6ae49474aa1916eb1ac27165cea228f4.cloudfront.net (CloudFront)
X-Amz-Cf-Id: VJaYDhmHHjpSAu9RX7REY61NbKcawTaxo9pZz50UDdSG9_fww_S3pw==
X-Amz-Cf-Pop: DFW3-C1
X-Amzn-Trace-Id: Root=1-5e49d639-9d3311f8599bb571ffd84f92;Sampled=0
X-Cache: Miss from cloudfront
x-amz-apigw-id: IA5o7H4VvHcFwKw=
x-amzn-RequestId: ba4e42a1-e63a-47e2-8dc9-7ad5ee0d2773

{
    "hello": "world"
}

Yay you created an API and called it!

If you look at your list of AWS Lambdas, you'll notice a new "intro-dev" lambda for the API. This one lambda will contain all API calls in it.

Finally, let's uncomment the rest of the lines in that app.py file so the whole file should now look like this...

from chalice import Chalice

app = Chalice(app_name='intro')

@app.lambda_function()
def hello_world(event, context):
    return {'hello': 'world'}

@app.lambda_function()
def hello_there_name(event, context):
    name = event['name']
    return {'hello': name}

@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.

Again, save and deploy. And this time let's try all three APIs...

# deploy latest
chalice deploy

# change to your deployed API URL
API_BASE=https://08ytd34hwk.execute-api.us-west-2.amazonaws.com/api/

# call the base url alone
http $API_BASE

# call new API with a URL parameter
http $API_BASE/hello/susan

# call the API that takes json a few different ways
curl -X POST --data '{"name": "Noah", "state": "Texas"}' -H "Content-Type: application/json" $API_BASE/users
http -v $API_BASE/users name=Noah state=Texas
http -b $API_BASE/users name=Noah state=Texas

If you get the error "message": "Missing Authentication Token" give it a few moments and try again. Lambdas recycle calls and may take up to a minute before the new code is deployed.

That's it! Pretty simple to get started.

Next Steps

There's so much more! Like...

  1. Try removing one of the @app.lambda_function() sections and redeploy. Notice that Chalice detects that lambda has been removed and automatically removes it from AWS.
  2. HTTPie is a very cool utility, like a modern CURL for web work. Checkout this great httpie cheatsheet.
  3. Take a look in the AWS API Gateway Console to see the APIs created
  4. You can get lambdas to trigger off of AWS events from S3, scheduled events, CloudWatch, SNS, and more. Just by decorating a method with one line. See event sources.
  5. There is a great Chalice Media Query Walkthrough to try out a bunch of features of Chalice and wire up different AWS services.

Created 2020-02-16 by Noah Coad
May want to check out the index of other gists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment