Supercharge Your Local AWS Lambda Development: A Guide to Using LocalStack with the Serverless Framework
Introduction
https://github.com/MohamedAljoke/estudo-localstack
LocalStack provides a fully functional local AWS cloud stack that simulates the AWS cloud environment, allowing developers to develop and test their serverless applications locally, without incurring any cloud costs. By leveraging LocalStack in conjunction with the Serverless Framework, developers can streamline their development workflow, iterate faster, and ensure the reliability of their applications before deploying them to the cloud.
Code
first create a docker-compose.yml with the localstack service.
#docker-compose.yml
version: '3.8'
services:
localstack:
image: localstack/localstack:latest
ports:
- '4566:4566'
environment:
- services=s3,sqs,lambda,logs,cloudformation,ec2,apigateway
- DEFAULT_REGION=us-east-1
- LAMBDA_EXECUTOR=docker
- LAMBDA_REMOTE_DOCKER=true
- LAMBDA_REMOVE_CONTAINERS=true
- DATA_DIR=/tmp/localstack/data
- DEBUG=1
- DOCKER_HOST=unix:///var/run/docker.sock
volumes:
- '${TMPDIR:-/tmp/localstack}:/tmp/localstack'
- '/var/run/docker.sock:/var/run/docker.sock'
start the container with
docker-compose up -d
now let´s create a simple nodejs handler with typescript
mkdir node_lambda
cd node_lambda
npm init -y
npm i typescript @types/node ts-node-dev serverless --save-dev
npx tsc --init --outDir build
touch main.ts
inside main.ts add this code
//main.ts
export async function handler(event: any) {
console.log('my_event', JSON.stringify(event));
return 'Hello world';
}
now the handler is finished let´s configure the serverless to create the lambda and define the lambda function, the handler points to the build folder in the main file.handler function that is exported from it
#serverless.yml
service: my-service-name
provider:
name: aws
runtime: nodejs18.x
region: us-east-1
stage: ${opt:stage, 'local'}
functions:
nodeLambdaHandler:
handler: build/main.handler
events:
- http:
path: /
method: ANY
with this we can already send the lambda to aws, now lets add serverless-localstack so that we can deploy the stack localy
npx serverless plugin install -n serverless-localstack
#serverless.yml
service: my-service-name
provider:
name: aws
runtime: nodejs18.x
region: us-east-1
stage: ${opt:stage, 'local'}
#add this code to use serverless-localstack when deploy on local stage
plugins:
- serverless-localstack
custom:
localstack:
stages:
- local
host: http://localhost
edgePort: 4566
functions:
nodeLambdaHandler:
handler: build/main.handler
events:
- http:
path: /
method: ANY
let´s add few comands to the package.json
{
//....
"scripts": {
"build": "tsc",
"deploy:local": "npm run build && npx serverless deploy --stage local",
"logs": "sls logs -t -f nodeLambdaHandler --stage local"
},
//....
}
so now if we do this comand it will send the lambda to the localstack
npm run deploy:local
you can run this comand to watch the lambda logs
npm run logs
we can add serverless offline to run the application
npx serverless plugin install -n serverless-offline
change the serverless.yml file
#serverless.yml
service: my-service-name
provider:
name: aws
runtime: nodejs18.x
region: us-east-1
stage: ${opt:stage, 'local'}
#add this code to use serverless-localstack when deploy on local stage
plugins:
- serverless-localstack
######add this line ->
- serverless-offline
custom:
localstack:
stages:
- local
host: http://localhost
edgePort: 4566
functions:
nodeLambdaHandler:
handler: build/main.handler
events:
- http:
path: /
method: ANY
and then update package.json scripts
{
//....
"scripts": {
"build": "tsc",
//add the start:dev
"start:dev": "npm run build && sls offline",
"deploy:local": "npm run build && npx serverless deploy --stage local",
"logs": "sls logs -t -f nodeLambdaHandler --stage local"
},
//....
}
we can make a bucket now and make the lambda trigger with file drop in the bucket, where we define resources. so the final form for our serverless.yml file is
service: serverless-localstack-app
provider:
name: aws
runtime: nodejs18.x
region: us-east-1
stage: ${opt:stage, 'local'}
plugins:
- serverless-localstack
- serverless-offline
custom:
localstack:
stages:
- local
host: http://localhost
edgePort: 4566
functions:
nodeLambdaHandler:
handler: build/main.handler
events:
- s3:
bucket: test-bucket-name
event: s3:ObjectCreated:*
rules:
- suffix: .pdf
- http:
path: /
method: ANY
resources:
Resources:
MyS3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: test-bucket-name
aws cli helper commands, adding the endpoint so we use localstack
aws --endpoint-url=http://localhost:4566 lambda list-functions \
--query "Functions[*].FunctionName" \
--output text
aws --endpoint-url=http://localhost:4566 s3 ls
we can use this command to send a pdf file to the s3 bucket on localstack wish will trigger the lambda function
aws --endpoint-url=http://localhost:4566 \
s3api put-object \
--bucket test-bucket-name \
--key dummyfile.pdf --body=dummyfile.pdf
the lambda will log the event with the s3 bucket data, and now you can handle the object as you want
#example of the log you will get
{
"Records": [
{
"eventVersion": "2.1",
"eventSource": "aws:s3",
"awsRegion": "us-east-1",
"eventTime": "2024-04-23T04:26:24.585Z",
"eventName": "ObjectCreated:Put",
"userIdentity": { "principalId": "AIDAJDPLRKLG7UEXAMPLE" },
"requestParameters": { "sourceIPAddress": "127.0.0.1" },
"responseElements": {
"x-amz-request-id": "3ebb59a3",
"x-amz-id-2": "eftixk72aD6Ap51TnqcoF8eFidJG9Z/2"
},
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "f29cf7eb",
"bucket": {
"name": "test-bucket-name",
"ownerIdentity": { "principalId": "A3NL1KOZZKExample" },
"arn": "arn:aws:s3:::test-bucket-name"
},
"object": {
"key": "dummyfile.pdf",
"sequencer": "0055AED6DCD90281E5",
"size": 5,
"eTag": "698dc19d489c4e4db73e28a713eab07b"
}
}
}
]
}