I am trying to test a lambda function locally, using serverless framework. This function is attached to a POST endpoint, defined as:
createCat:
handler: app/handler.createCat
events:
- http:
path: cats/
method: post
I invoke the function locally a according to this source:
# Command line
serverless invoke local --function createCat --path local-invoke/createCat.json --stage local
# createCat.json
{
"body": {
"name": "Cat cat blue",
"age": 4,
"color": "blue"
}
}
I am trying to parse the body and get the items like it is shown here, but it does not work:
import { Context } from 'aws-lambda';
const createCat = async (event: any, context?: Context) => {
try{
const data = JSON.parse(event.body)
let name = data?.name
let age = Number(data?.age)
let color = data?.color
return {
statusCode: 500,
message: data
}
}
catch(error) {
return {
statusCode: 500,
body: JSON.stringify({
message: getMessageFromError(error)
})
}
}
}
I am getting this output, instead of the parsed body:
{
"statusCode": 500,
"body": "{\"message\":\"Unexpected token l in JSON at position 0\"}"
}
Serverless documentation on local invoke does not touch on how to pass/retrieve body params either.
What am I doing wrong here?
When invoking the deployed lambda, event.body
is a scaped JSON string. However, when invoking locally with serverless invoke local
, it is an object literal in javascript, and the parsing error happens since it is trying to parse this object literal.
I wrote a helper function to help cover both cases seamlessly:
// types.ts
export interface ParsedEvent {
body: any | undefined,
pathParameters: any | undefined
}
// util.ts
import { ParsedEvent } from "./types"
export const parseEvent = (event: any) : ParsedEvent => {
let parsedEvent : ParsedEvent = {
body: undefined,
pathParameters: undefined
}
parsedEvent.pathParameters = event?.pathParameters
// Parse body if it is stringified JSON
if(typeof event?.body === 'string' )
{
parsedEvent.body = JSON.parse(event?.body)
} else {
parsedEvent.body = event?.body
}
return parsedEvent
}
and use it as:
import { Context } from 'aws-lambda';
import { parseEvent } from './util.js';
const createCat = async (event: any, context?: Context) => {
let parsedEvent = parseEvent(event)
// body params
let name = parsedEvent.body?.name
let age = parsedEvent.body?.age
// path params
let id = parsedEvent.pathParameters?.id
}