DEV Community

Cover image for Build Serverless Applications using CDK and SAM
Lorenz Vanthillo for AWS Community Builders

Posted on

Build Serverless Applications using CDK and SAM

AWS recently announced the public preview of Serverless Application Model (SAM) support for CDK. SAM is an open-source framework that can be used to build, test and deploy serverless applications on AWS. It provides a Lambda-like execution environment that lets you locally build, test, and debug applications. Previously this could only be defined by SAM templates but now it is also possible through the AWS Cloud Development Kit (CDK)!

alt text

I will guide you through a small demo project to demonstrate how to build a serverless application with AWS CDK and test it locally with AWS SAM.

We will build a simple REST API which shows the current bid or ask price of a certain cryptocurrency on Binance (exchange), expressed in the value of Bitcoin.

The API expects two query parameters:

  • coin: (ETH, DOG, LINK, DOT, ...)
  • type: (bid or ask price)

Example of the API call:

$ curl "http://127.0.0.1:3000/crypto?type=ask&coin=ETH"
{"coin": "ETH", "price": 0.066225}
Enter fullscreen mode Exit fullscreen mode

The setup in AWS will also be pretty straight forward.
We will set up a Lambda proxy integration in API Gateway

alt text

To get started, we need to install the AWS CDK CLI and create a new CDK project. I use Python as client language.

$ npm install -g aws-cdk
$ cdk init app --language python
Enter fullscreen mode Exit fullscreen mode

The project structure looks like this:

.
├── README.md
├── app.py
├── cdk.json
├── requirements.txt
├── sam_cdk_demo
│   ├── __init__.py
│   └── sam_cdk_demo_stack.py
└── setup.py
Enter fullscreen mode Exit fullscreen mode

The file sam_cdk_demo/sam_cdk_demo_stack.py should contain our code to define the AWS cloud resources we need but first let's start with writing our Lambda.

Create a folder inside the root of the project called "lambda" and add a handler.py. The ccxt library is used by our Lambda to interact with the Binance API. The Lambda itself is very basic on purpose.

import ccxt
import json


# use CCXT library to connect with Binance API
exchange = getattr(ccxt, 'binance')({
    'timeout': 3000,
    'enableRateLimit': True
})

def get_current_price(coin_name, price_type):
    # fetch latest ticker data for coin pair xxx/BTC
    ticker = exchange.fetch_ticker('{}/BTC'.format(coin_name))
    # get ask/bid price from ticket data
    current_price = ticker[price_type]
    return current_price

def lambda_handler(event, context):
    # get values from query string parameters
    coin = event['queryStringParameters']['coin']
    price = event['queryStringParameters']['type']

    # CCXT exchange expects coin in uppercase
    valid_coin = coin.upper()

    # get current price based on coin name and price type (ask/bid)
    current_price = get_current_price(valid_coin, price)

    return {
        'statusCode': 200,
        'headers': { 
            'Content-Type': 'application/json'
        },
        'body': json.dumps({
            'coin': valid_coin,
            'price': current_price,
        })
    }
Enter fullscreen mode Exit fullscreen mode

Don't forget to add a requirements.txt inside the folder to make the ccxt library available to the Lambda.

ccxt==1.50.13
Enter fullscreen mode Exit fullscreen mode

The Lambda is ready! Now we will use AWS CDK to define our AWS infrastructure. We need to deploy the Lambda and create an API Gateway in front of it. Update the file demo/demo_stack.py. We keep the code pretty basic again.

from aws_cdk import (
    aws_lambda as _lambda,
    aws_apigateway as apigw,
    core,
)

class CdkLambdaSamStack(core.Stack):

    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # creating Lambda function that will be triggered by the API Gateway
        get_price_handler = _lambda.Function(self,'CryptoFunction',
            handler='handler.lambda_handler',
            runtime=_lambda.Runtime.PYTHON_3_8,
            code=_lambda.Code.asset('lambda'),
            timeout=core.Duration.seconds(30),
        )

        # create REST API
        api = apigw.RestApi(self, 'crypto-api')

        # add resource /crypto
        resource = api.root.add_resource('crypto')

        # create Lambda integration 
        get_crypto_integration = apigw.LambdaIntegration(get_price_handler)

        # add method which requires two query string parameteres (coin and type)    
        resource.add_method(
            http_method='GET',
            integration=get_crypto_integration,
            request_parameters={
                'method.request.querystring.coin': True,
                'method.request.querystring.type': True
            },
            request_validator_options=apigw.RequestValidatorOptions(validate_request_parameters=True)
        )
Enter fullscreen mode Exit fullscreen mode

Update the requirements.txt in the project root with the necessary modules.

aws-cdk.core
aws-cdk.aws_lambda
aws-cdk.aws_apigateway
Enter fullscreen mode Exit fullscreen mode

Start the Python virtual environment which is created by CDK and install the modules.

$ source .venv/bin/activate
(.venv)$ pip3 install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

We will use AWS SAM to test our setup locally. It's important to mention that you need to have Docker installed. We will use Docker to build our code. The Lambda will also run inside as a Lambda-like Docker container.

Prepare the deployment artifact.

(.venv)$ sam-beta-cdk build --use-container
Enter fullscreen mode Exit fullscreen mode

Start the local API Gateway.

$ sam-beta-cdk local start-api
...
* Running on http://127.0.0.1:3000/
Enter fullscreen mode Exit fullscreen mode

We can use a tool like Postman (or curl or just your browser) to perform calls against our API.

alt text

It takes a few seconds to execute the function because AWS SAM is spinning up a Docker container to execute our code. After the execution the container is destroyed.

When everything looks fine we can deploy it to AWS.

(.venv)$ cdk bootstrap
(.venv)$ cdk deploy -a .aws-sam/build
Enter fullscreen mode Exit fullscreen mode

Now test against the deployed API.
alt text

alt text

We were able to test our API and Lambda using the new Serverless Application Model integration with CDK! You can find all code on my GitHub. Be aware that this feature is in preview. Feel free to do more extensive testing. You can report bugs and submit feature requests to the SAM opensource repository.

Top comments (1)

Collapse
 
_gerald20 profile image
Gerald Stewart

This is awesome, I'll have to give it a try in TypeScript/JavaScript!