More

    Deploying an AWS Chalice Application with the AWS Cloud Development Kit

    Building a User Management Service with AWS API Gateway, Lambda, and DynamoDB

    Welcome to this exciting journey where we’ll create a simple user management service using Amazon API Gateway, AWS Lambda, and Amazon DynamoDB! By leveraging the AWS Cloud Development Kit (CDK) and AWS Chalice, we’ll build our infrastructure and application logic as code. These frameworks allow us to automate deployments and manage code efficiently. Let’s dive in!

    Overview of the AWS Frameworks

    AWS Cloud Development Kit (CDK) is a powerful open-source framework that allows you to define cloud infrastructure using familiar programming languages such as Python, Java, TypeScript, and more. In our case, we’ll use Python to create a robust architecture.

    On the flip side, AWS Chalice is a Python microframework specifically designed for building serverless applications. It simplifies the development of applications utilizing API Gateway and Lambda. Chalice automates many resource definitions, such as creating Swagger documentation and managing application configurations.

    By combining CDK for infrastructure and Chalice for application logic, we achieve a seamless and synchronized development environment.

    Architecture Considerations

    When using CDK and Chalice together, determining where to manage the IAM roles for your Lambda functions can be a gray area. We will opt to create the IAM role using CDK. This approach allows us to maintain a single SAM template definition that we can use across different environments, simplifying deployment.

    For instance, the Lambda function’s memory size and timeout can also be specified within Chalice, as long as these parameters remain constant across environments.

    Prerequisites

    To get started, make sure you have the CDK CLI installed by running:

    bash
    npm install -g aws-cdk

    Building the Application Logic

    1. Setting Up: First, let’s create a directory for our project and set up the Chalice web API.

      bash
      mkdir users-service
      cd users-service
      python3 -m venv .venv
      source .venv/bin/activate
      pip install chalice==1.12.0
      chalice new-project web-api
      cd web-api

    2. Adding Dependencies: We will use the Boto3 library alongside Chalice. Update the requirements.txt file:

      bash
      echo “boto3==1.10.30” > requirements.txt
      echo “chalice==1.12.0” >> requirements.txt
      pip install -r requirements.txt

    3. Writing the Code: Open app.py and replace its content with the following code:

      python
      import os
      import boto3
      from chalice import Chalice

      app = Chalice(app_name=”web-api”)
      dynamodb = boto3.resource(‘dynamodb’)
      dynamodb_table = dynamodb.Table(os.environ[‘DYNAMODB_TABLE_NAME’])

      @app.route(‘/users’, methods=[‘POST’])
      def create_user():
      user = app.current_request.json_body
      dynamodb_table.put_item(Item=user)
      return user

      @app.route(‘/users/{username}’, methods=[‘GET’])
      def get_user(username):
      response = dynamodb_table.get_item(Key={‘username’: username})
      return response[‘Item’]

      @app.route(‘/users/{username}’, methods=[‘DELETE’])
      def delete_user(username):
      dynamodb_table.delete_item(Key={‘username’: username})

    The above code snippet implements a basic web API for managing users in DynamoDB, handling user creation, retrieval, and deletion.

    Building the Infrastructure Logic

    1. Create a New CDK Project:

      Navigate back to the root directory and create a new folder for infrastructure.

      bash
      cd ..
      mkdir infra
      cd infra
      cdk init –language python –generate-only
      rm -rf infra
      rm setup.py

    2. Set Up Dependencies: Update the requirements.txt file in the CDK project:

      bash
      echo “aws_cdk.aws_dynamodb==1.19.0” > requirements.txt
      echo “aws_cdk.core==1.19.0” >> requirements.txt
      echo “cdk-chalice==0.4.0” >> requirements.txt
      pip install -r requirements.txt

    3. Create the Stack: Create a new stacks package with the web_api.py module:

      bash
      mkdir stacks
      touch stacks/init.py
      touch stacks/web_api.py

    4. Define the Stack Logic: Open stacks/web_api.py and add the following code:

      python
      import os
      from aws_cdk import (
      aws_dynamodb as dynamodb,
      aws_iam as iam,
      core as cdk
      )
      from cdk_chalice import Chalice

      class WebApi(cdk.Stack):

      def __init__(self, scope: cdk.Construct, id: str, **kwargs) -> None:
          super().__init__(scope, id, **kwargs)
      
          partition_key = dynamodb.Attribute(name="username", type=dynamodb.AttributeType.STRING)
          self.dynamodb_table = dynamodb.Table(self, 'UsersTable', partition_key=partition_key, removal_policy=cdk.RemovalPolicy.DESTROY)
          cdk.CfnOutput(self, 'UsersTableName', value=self.dynamodb_table.table_name)
      
          lambda_service_principal = iam.ServicePrincipal('lambda.amazonaws.com')
          self.api_handler_iam_role = iam.Role(self, 'ApiHandlerLambdaRole', assumed_by=lambda_service_principal)
          self.dynamodb_table.grant_read_write_data(self.api_handler_iam_role)
      
          web_api_source_dir = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, 'web-api')
          chalice_stage_config = self._create_chalice_stage_config()
          self.chalice = Chalice(self, 'WebApi', source_dir=web_api_source_dir, stage_config=chalice_stage_config)
      
      def _create_chalice_stage_config(self):
          return {
              'api_gateway_stage': 'v1',
              'lambda_functions': {
                  'api_handler': {
                      'manage_iam_role': False,
                      'iam_role_arn': self.api_handler_iam_role.role_arn,
                      'environment_variables': {
                          'DYNAMODB_TABLE_NAME': self.dynamodb_table.table_name
                      },
                      'lambda_memory_size': 128,
                      'lambda_timeout': 10
                  }
              }
          }

    This code defines the infrastructure for our user management service, including the creation of a DynamoDB table and the necessary IAM roles for our Lambda function.

    1. Deploying the Stack: Now, alter app.py to include the new stack:

      python
      import os
      from aws_cdk import core as cdk
      from stacks.web_api import WebApi

      app = cdk.App()

      dev_env = cdk.Environment(account=os.environ[‘CDK_DEFAULT_ACCOUNT’], region=os.environ[‘CDK_DEFAULT_REGION’])
      prod_eu_west_1_env = cdk.Environment(account=”123456789012″, region=’eu-west-1′)
      prod_us_east_1_env = cdk.Environment(account=”123456789012″, region=’us-east-1′)

      WebApi(app, ‘WebApiDev’, env=dev_env)
      WebApi(app, ‘WebApiProdEuWest1’, env=prod_eu_west_1_env)
      WebApi(app, ‘WebApiProdUsEast1’, env=prod_us_east_1_env)

      app.synth()

    Testing Your API

    Once all the configurations are in place, it’s time to deploy the development stack:

    bash
    cdk synth
    cdk deploy WebApiDev

    Upon successful deployment, you will receive output with the API endpoint. You can test your new user management API using curl:

    bash
    curl -H “Content-Type: application/json” -X POST -d ‘{“username”:”john”, “email”:”john@example.com”}’ https://n6doqg3ewl.execute-api.eu-west-1.amazonaws.com/v1/users

    Local Testing

    For local testing, you can start the Chalice local server:

    bash
    env DYNAMODB_TABLE_NAME=YourTableName chalice local

    This will let you test your API endpoints locally against a pre-created DynamoDB table.

    Cleanup Resources

    Finally, when you no longer need the infrastructure, execute:

    bash
    cdk destroy WebApiDev

    This command will remove all the AWS resources created during your project lifecycle.

    Insightful Takeaways

    By combining AWS CDK and AWS Chalice, you effectively streamline your development process while adhering to industry standards for best practices in infrastructure as code. This approach makes it easier to manage and deploy serverless applications in a more organized, efficient, and scalable manner, driving down the complexities usually associated with cloud service management.

    Latest articles

    Related articles

    Leave a reply

    Please enter your comment!
    Please enter your name here

    Popular