DEV Community

Ahmed Salem
Ahmed Salem

Posted on

Building and Integrating Lambda Layers with Serverless API

In this tutorial, we’ll explore how to use AWS Lambda Layers to organize and reuse code across multiple AWS Lambda functions. Specifically, we’ll move DynamoDB queries to a separate Lambda Layer and integrate it with a Serverless API. This approach enhances maintainability and promotes code reuse, making your serverless applications more scalable and efficient.

Overview

Our solution involves creating a Lambda Layer containing DynamoDB operations (list, add, and get countries) and integrating this layer with our existing Serverless API. We will define the required resources using the Serverless Framework and deploy them to AWS.

Architecture

Image description
The architecture includes:

  • A DynamoDB table to store country information.
  • A Lambda Layer to encapsulate DynamoDB operations.
  • Multiple Lambda functions to handle API requests (add, list, get countries).
  • API Gateway to expose these Lambda functions as RESTful endpoints.

Directory Structure

Here is the directory structure for our project:
Image description

Step-by-Step Guide
1. Create a Separate Folder for Lambda Layers
Create a folder named Dynamo_layer and add the following:

  • A folder named modules-layer.
  • A folder named dynamo-sdk-layer.
  • A serverless.yml file.

2. Add Layers Resources in serverless.yml
In the Dynamo_layer directory, add the following content to serverless.yml:

# Service name has to be unique for your account.
service: my-dependencies

# framework version range supported by this service.
frameworkVersion: ">=1.1.0 <8.0.0"

# configuration of the cloud provider. As we are using AWS so we defined AWS corresponding configuration.
provider:
  name: aws
  lambdaHashingVersion: 20201221
  runtime: nodejs14.x
  #stage: dev
  region: us-east-2
  # Create an ENV variable to be able to use it in my JS code. *** Check line 4 in get-country-by-name JS file ***
  environment:
    tableName: ${self:custom.tableName}
  # To Give a permission to each lambda function to access DynamoDB table
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:*
        # - dynamodb:Query
        # - dynamodb:Scan
        # - dynamodb:GetItem
        # - dynamodb:PutItem
      Resource: "*"

layers:
  ModulesLayer:
    path: ./modules-layer
    description: "my dependencies"

  DynamoSdkLayer:
    path: ./dynamo-sdk-layer
    description: "my dynamo dependencies"

custom:
  tableName: countries
Enter fullscreen mode Exit fullscreen mode

3. Deploy Lambda Layers

Deploy the Dynamo_layer to create a CloudFormation stack for Lambda Layers by running the following command:

sls deploy

Enter fullscreen mode Exit fullscreen mode

4. Navigate to the my-service folder, which contains the serverless.yml file for your API Gateway endpoints and Lambda functions.
Ensure the configuration includes:

  • A DynamoDB table.
  • Lambda functions for countries_loadData, add-country, list-countries, and get-country-by-name.

serverless.yml

# Service name has to be unique for your account.
service: my-service

# framework version range supported by this service.
frameworkVersion: ">=1.1.0 <8.0.0"

# configuration of the cloud provider. As we are using AWS so we defined AWS corresponding configuration.
provider:
  name: aws
  lambdaHashingVersion: 20201221
  runtime: nodejs14.x
  #stage: dev
  region: us-east-2
  # Create an ENV variable to be able to use it in my JS code. *** Check line 4 in get-country-by-name JS file ***
  environment:
    tableName: ${self:custom.tableName}
    NODE_PATH: "./:/opt/node_modules"
  # To Give a permission to each lambda function to access DynamoDB table
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:*
        # - dynamodb:Query
        # - dynamodb:Scan
        # - dynamodb:GetItem
        # - dynamodb:PutItem
      Resource: "*"

# package:
#   exclude:
#     - Dynamo-SDK/**

custom:
  tableName: countriees         

# As shown below, when the HTTP POST or GET request is made, the handler should be invoked.
functions:

#(1) Lambda function to initially fill DynamoDB
  FillDynamoDB:
    handler: lambdas/countries_loadData.fill
    description: fill DynamoDB table with set of countries.
    events:
      - http: 
          path: fill-dynamoDB
          method: POST
          cors: true
    layers:
      - arn:aws:lambda:us-east-2:<ACCOUNT-ID>:layer:ModulesLayer:3
      - arn:aws:lambda:us-east-2:<ACCOUNT-ID>:layer:DynamoSdkLayer:3

#(2) Lambda function to list all the countries 
  GetAllCountries:
    handler: lambdas/list-countries.list
    description: get all the countries information.
    events:
      - http: 
          path: list-countries
          method: GET
          cors: true
    layers:
      - arn:aws:lambda:us-east-2:<ACCOUNT-ID>:layer:ModulesLayer:3
      - arn:aws:lambda:us-east-2:<ACCOUNT-ID>:layer:DynamoSdkLayer:3

#(3) Lambda function to get a country by name
  GetCountryByName:
    handler: lambdas/get-country-by-name.get
    description: get country By Name.
    events:
      - http: 
          path: get-country/{NAME}
          method: GET
          cors: true
    layers:
      - arn:aws:lambda:us-east-2:<ACCOUNT-ID>:layer:ModulesLayer:3
      - arn:aws:lambda:us-east-2:<ACCOUNT-ID>:layer:DynamoSdkLayer:3

#(4) Lambda function to add a new country 
  AddNewCountry:
    handler: lambdas/add-country.add
    description: add a new country.
    events:
      - http: 
          path: add-country
          method: POST
          cors: true
    layers:
      - arn:aws:lambda:us-east-2:<ACCOUNT-ID>:layer:ModulesLayer:3
      - arn:aws:lambda:us-east-2:<ACCOUNT-ID>:layer:DynamoSdkLayer:3



#Resources are AWS infrastructure components which your Functions use. 
#The Serverless Framework deploys an AWS components your Functions depend upon.
resources:
  Resources:
    myDynamoDbTable:
      Type: 'AWS::DynamoDB::Table'
      #DeletionPolicy: Retain
      Properties:       
        TableName: ${self:custom.tableName}

        AttributeDefinitions:
          -
            AttributeName: "NAME"
            AttributeType: "S" 

        KeySchema:
          -
            AttributeName: "NAME"
            KeyType: "HASH"

        BillingMode: PAY_PER_REQUEST

    # Custom resource to invoke lambda function to fill the countries DynamoDB table
    TriggerFillDynamoDBFunction:
     Type: AWS::CloudFormation::CustomResource
     Properties:
       ServiceToken: !GetAtt 'FillDynamoDBLambdaFunction.Arn'
Enter fullscreen mode Exit fullscreen mode

5. Deploy Serverless API

Deploy the serverless configuration by running:

sls deploy

Enter fullscreen mode Exit fullscreen mode

6. Access API Endpoints

You can access the endpoints using the following URLs:

List countries: GET

https://nymaeazapc.execute-api.us-east-2.amazonaws.com/dev/list-countries
Enter fullscreen mode Exit fullscreen mode

Get country by name: GET

https://nymaeazapc.execute-api.us-east-2.amazonaws.com/dev/get-country/{NAME}
Enter fullscreen mode Exit fullscreen mode

Add a country: POST

https://nymaeazapc.execute-api.us-east-2.amazonaws.com/dev/add-country

Enter fullscreen mode Exit fullscreen mode

7. Remove All Functions, Events, and Resources

To clean up, remove all AWS resources created by running:

sls remove

Enter fullscreen mode Exit fullscreen mode

Conclusion

By following these steps, you have successfully utilized AWS Lambda Layers to modularize and reuse DynamoDB queries across multiple Lambda functions. This approach demonstrates the power of Lambda Layers in promoting code reuse and maintainability, making your serverless applications more efficient and scalable.

Top comments (1)

Collapse
 
luiz_couto_4030a9c955532a profile image
Luiz Couto

Very nice, i will try, thanks!