dherault / dherault/serverless-offline

How to run lambda integration mode in serverless locally

Open
#1,724 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
5.3k
Forks
811
Avg merge
2d 4h
Merged PRs (30d)
3

Description

I want to run serverless application locally earlier this was working using lambda proxy but I want to change it to lambda integration. So I have defined request and response template as follows but when I invoke lambda locally, I see this response,

{
"isBase64Encoded": false,
"statusCode": 200,
"headers": {
"access-control-allow-origin": "*",
"content-type": "application/json; charset=utf-8",
"content-length": "2",
"etag": "W/\"2-l9Fw4VUO7kr8CvBlt4zaMCqXZ0w\""
},
body
:
"{\"error\":\"[{\\\"error\\\":\\\"Invalid query parameters\\\",\\\"messages\\\":[\\\"'page' is required\\\",\\\"'pagesize' is required\\\"]}]\"}"
}
and I expect only body in response this breaks running UI locally , when I run the application in aws I get correct response. Is there any additional configuration to be done in serverless.yml. This is how serverless.yml looks like

service: my-service-api

provider:
name: aws
runtime: nodejs16.x
memorySize: 256
timeout: 10
region: us-west-2
profile: xyz
versionFunctions: false
endpointType: regional
deploymentBucket:
name: ps-serverless
vpc: xyz
apiGateway:
restApiId: xyz
restApiRootResourceId: xyz
restApiResources:
/district-settings: xyz
plugins:
- serverless-offline

custom:
corsOptions:
origin: http://localhost:3000/
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
- X-Xsrf-Token
allowCredentials: true
requestTemplate:
application/json: |
#set($request_header = $input.params().header)
#set($request_query = $input.params().querystring)
#set($request_path = $input.params().path)
#set($request_stage_vars = $stageVariables)
#set($request_context = $context)
{
"body": "$util.escapeJavaScript($input.json('$'))",
"httpMethod": "$context.httpMethod",
"headers": {
#foreach($header in $request_header.keySet())
"$header" : "$util.escapeJavaScript($request_header.get($header))"
#if($foreach.hasNext),#end
#end
},

"queryStringParameters": {
#foreach($query in $request_query.keySet())
"$query" : "$util.urlDecode($request_query.get($query))"
#if($foreach.hasNext),#end
#end
},

"pathParameters": {
#foreach($path in $request_path.keySet())
"$path" : "$util.escapeJavaScript($request_path.get($path))"
#if($foreach.hasNext),#end
#end
},

"stageVariables": {
#foreach($stage in $request_stage_vars.keySet())
"$stage" : "$util.escapeJavaScript($request_stage_vars.get($stage))"
#if($foreach.hasNext),#end
#end
},
"resource": "$context.resourcePath",
"path":"$context.path",
"requestContext": {
#foreach($reqContext in $request_context.keySet())
"$reqContext" : "$util.escapeJavaScript($request_context.get($reqContext))"
#if($foreach.hasNext),#end
#end
},
"isBase64Encoded": false
}

responseHeaders:
headers:
Content-Type: ${env:CONTENT_TYPE}
Access-Control-Allow-Credentials: ${env:ALLOW_CREDENTIAL}
Strict-Transport-Security: ${env:SECURE_TRANSPORT_SECURITY}
Cache-Control: ${env:CACHE_CONTROL}
Content-Security-Policy: ${env:DEFAULT_CSP}
X-Content-Type-Options: ${env:CONTENT_TYPE_OPTIONS}
X-XSS-Protection: ${env:XSS_PROTECTION}
X-Frame-Options: ${env:X_FRAME_OPTIONS}
Pragma: ${env:PRAGMA}

statusCodes:
200:
pattern: ''
template:
application/json: |
#set($body = $input.json('$.body'))
#set($statusCode = $input.json('$.statusCode'))
#set($Integer = 0)
$util.parseJson($body)
#set($origin = $input.params().header)
#set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)
#if($body.contains("error"))
#set($context.responseOverride.status = $Integer.parseInt($statusCode))
#end

functions:
listDistricts:
handler: src/districts/district-handler.list
events:
- http:
path: 'district'
method: get
cors: ${self:custom.corsOptions}
integration: lambda
request:
passThrough: NEVER
template: ${self:custom.requestTemplate}
response: ${self:custom.responseHeaders}

Any additional configuration I need to configure to get correct only body in response running locally will be of great help. Also I have GET request with query params that is not passed.

Please note I am using serverless-offline@8.8.1, node version 16. I am running app locally using sls offline start.

this is the lambda code

async (req: Request, res: Response, next: NextFunction): Promise => {
try {
const districtListQueryParam: DistrictListQueryParam = (req.query as unknown) as DistrictListQueryParam;

const districtList = <>
res.status(HttpStatusCodes.OK).send(districtList);
} catch (err) {
logger.error(`Error while listing the districts ${err.message}`);
next(err);
}
}
This is the error message in terminal from catch ,

{"filename":"http-error-middleware.js","level":"error","message":"Error: [{\"error\":\"Invalid query parameters\",\"messages\":[\"'page' is required\". ....
Replies:1 comment

karthikpower
2 days ago
Author
[offline] _____ REQUEST TEMPLATE PROCESSING _____
[offline] Velocity rendered: {
"body": "{}",
"httpMethod": "GET",
"headers": {
"Host" : "localhost:3000"
, "Connection" : "keep-alive"
, "sec-ch-ua" : ""Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115""
, "Accept" : "application/json, text/plain, /"
, "sec-ch-ua-mobile" : "?0"
, "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"
, "sec-ch-ua-platform" : ""macOS""
, "Origin" : "http://localhost:8000/"
, "Sec-Fetch-Site" : "same-site"
, "Sec-Fetch-Mode" : "cors"
, "Sec-Fetch-Dest" : "empty"
, "Referer" : "http://localhost:8000/"
, "Accept-Encoding" : "gzip, deflate, br"
, "Accept-Language" : "en-GB,en-US;q=0.9,en;q=0.8"
},

"queryStringParameters": {
"page" : '1'
, "pagesize" : '12'
},
....

[offline] event: {}

This is what I see in terminal : though request template is processed but event is printed as empty. Though I have serverless-offline plugin

Contributor guide

Open the contributing guide

Research direction

Reproduce the GET district request with sls offline start using the shown serverless.yml, request template, response template, and src/districts/district-handler.list entry point. Compare the rendered request with the empty event and verify that query parameters reach the handler and that the local response contains only the expected body, matching AWS behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, javascript, node.js
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.