Supercharge Your AWS Lambda: Accelerate Development with a Low-Code Lambda Layer

Unlock the full potential of AWS Lambda and expedite your development process with the magic of low-code layers.

Raywall Malheiros
6 min readSep 22, 2023

Developing high-quality software is tough, and it can be expensive. It’s not just about creating a feature; you also need to think about testing scenarios, user experience, usability, cost, request volume, scalability, resilience, and observability. Besides achieving the feature’s goals, the software must also avoid causing disruptions during deployment. Oh, I almost forgot an important detail — it usually needs to be built quickly, which is often our main challenge.

When it comes to time, cloud development’s continuous evolution, along with code reuse and agile software practices, has sped up the creation and deployment of new features, simplifying and making infrastructure setup safer and faster.

The idea of paying only for what you use, along with not having to spend money on infrastructure maintenance and the availability of serverless cloud resources, has helped companies reduce costs, scale more easily, and improve project resilience. However, sometimes we don’t take full advantage of the cloud’s potential due to company security and architectural requirements.

To simplify, let’s imagine a hypothetical scenario: Picture a financial company with its infrastructure on AWS Cloud. They use an API Gateway to manage various services, all related to their loan agreements.

Many of these services handle basic data processing tasks, such as reading from or writing to DynamoDB tables. However, due to architectural guidelines, a direct connection between the API Gateway and DynamoDB is not allowed, so they use AWS Lambda or another service to facilitate the requests.

To make it more realistic, consider that the company tightly controls, manages, and audits the entire CI/CD process. As a developer, you often spend a significant amount of time configuring and adapting multiple files in the repository to deploy your project.

Finally, remember that you won’t be developing just one or two AWS Lambda Functions, but rather all the microservices for the product. This means your team will need to create many functions, possibly dozens or even hundreds, for this project.

In this situation, saving time and effort during software development is highly valuable, right? Well, this is precisely what the concept of ‘lambda low-code’ aims to achieve. With the goal of cutting down development time and encouraging code reuse, this project allows you to create a Lambda integration simply by specifying the resources and rules in a JSON-based configuration file.

Let’s take a look at how the low-code Lambda works!

AWS Low-Code Lambda

The project’s idea is to create a logic that can read a JSON-based configuration file containing specified resources and rules and set up the Lambda to perform only the specified actions.

Let’s revisit the earlier example we discussed about the financial company’s infrastructure, but this time, we’ll focus on a few methods to illustrate the concept.

In this case, we’ve three services and two different databases. The first service retrieves agreement data, the second one creates new agreements, and the third one retrieves information about the financial company’s clients. Each of these services uses a Lambda to facilitate the request between the API Gateway and the respective database.

Normally, we would have to write the code for each of these Lambda functions. However, to reduce the development effort, you can use Node.js to create a code capable of reading a JSON-based file with instructions to orchestrate the Lambda functions.

Essentially, this JSON file will contain resources and rules. The resources represent the microservices used, and the rules specify what the Lambda needs to do.

Let’s look at the first microservice: it handles a GET request at /v1/loans/{loanId} and retrieves loan data from the ‘loans’ DynamoDB table, using ‘loanId’ as the partition key. Here’s an example of how the JSON file appears:

// settings.json

{
"resources": [
{
"type": "api",
"method": "GET",
"path": "/v1/loans/{loanId}"
},
{
"type": "dynamodb",
"table": "loans",
"pk": "loanId",
"sk": null
}
],
"rules": [
{
"resources": "dynamodb",
"action": "get",
"from": "api"
}
]
}

In this file, we provide information about two resources: an API Gateway method and a DynamoDB table. In the rules section, we specify that the application should only accept GET requests at the path /v1/loans with the loanId included in the path. It should then retrieve data from the DynamoDB table using the received partition key (PK) to respond to the API request.

// lowcode-lambda-layer

const { insertItem, updateItem, deleteItem, getItem } = require("./data/dynamo.js")
const { formatResponse, formatError, getVariables, checkPath } = require("./util/functions.js")
const { resourceType, actionType } = require("./util/types.js")

exports.lowcodeLambda = async function(event, context, config) {
try {
const rule = config.rules[0]
const api = config.resources.find(r =>
r.type === rule.from **
r.method === event.httpMethod,
checkPath(event.path, r.path))

if (!api)
return formatError(404, "method not found")

const variables = getVariables(event.path, api.path)

switch (rule.resources) {
case resourceType.DynamoDB:
if (rule.action == actionType.Insert) {
var params = {
TableName: config.resources.find( r => r.type === rule.resourceType),
Item: JSON.parse(event.body)
}
return formatResponse(201, JSON.stringfy(await insertItem(params)))
}

else if (rule.action == actionType.Query) {
var params = {
TableName: config.resources.find( r => r.type === rule.resourceType),
Key: variables
}
return formatResponse(200, JSON.stringfy(await getItem(params)))
}
default:
break;
}
}
}

catch(error) {
return formatError(error.statusCode, error.message)
}

return formatResponse(200, "Ok")
}

When we examine the low-code module, we can see that it can interpret the configuration and perform precisely what is specified in the configuration file.

Reusing Code with Lambda Layers

This straightforward solution can reduce project development time, but we can enhance it further by incorporating Lambda layers.

Using Lambda layers, we can reuse the low-code module in any Lambda function we create, eliminating the need to duplicate the module code in each function.

# template.yaml

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: AWS SAM template for low-code lambda function

Globals:
Function:
MemorySize: 128
Timeout: 300

Metadata:
AWS::ServerlessRepo::Application:
Name: aws-lowcode-lambda
Author: Raywall Malheiros
Labels: ['aws', 'lowcode', 'lambda', 'development', 'integration', 'api', 'rest', 'gateway', 'low-code']
HomePageUrl: https://github.com/raywall/aws-lowcode-lambda
SemanticVersion: 0.0.2
SourceCodeUrl: https://github.com/raywall/aws-lowcode-lambda

Resources:
UserTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: loans
AttributeDefinitions:
- AttributeName: loanId
AttributeType: S
KeySchema:
- AttributeName: loanId
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 2
WriteCapacityUnits: 2

ApiGateway:
Type: AWS::Serverless::Api
Properties:
StageName: dev
DefinitionUri: ./infra/swagger.yaml
MethodSettings:
- ResourcePath: /{proxy+}
HttpMethod: POST

LowCodeLayer:
Type: AWS::Serverless::LayerVersion
Metadata:
BuildMethod: nodejs14.x
Properties:
LayerName: lambda-lowcode-layer
ContentUri: ./layer
CompatibleRuntimes:
- nodejs14.x
RetentionPolicy: Retain

LambdaFunction:
Type: AWS::Serverless::Function
Metadata:
BuildMethod: nodejs14.x
Properties:
CodeUri: ./app
Handler: index.app
FunctionName: lambda-lowcode-app
Runtime: nodejs14.x
Events:
ApiEvent:
Type: Api
Properties:
Path: '/{proxy+}'
Method: ANY
RestApiId:
Ref: ApiGateway
Auth:
Authorizer: NONE
Layers:
- !Ref LowCodeLayer

If you reference the low-code layer in the Lambda function, you’ll be able to import the module into the Lambda code and use its functions easily.

// lambda - index.js

const { lowcodeLambda } = require("/opt/nodejs/lowcode-lambda-layer");
const config = require("./setting.json");

exports.handler = async (event, context) => {
return lowcodeLambda(event, context, config)
}

In this case, your code only needs to perform simple validations and data processing before calling the low-code Lambda function.

This straightforward project can speed up the software development process, allowing you to concentrate on the more complex aspects of your solution.

If you want to view the sample project’s code, you can access the GitHub repository here

I hope you liked, and I see you in the next week, bye!

--

--

Raywall Malheiros

Senior Software Engineer and TechLead at Itaú Unibanco | 4x AWS Certified