Skip to content

My Lambda function is not returning the correct response when I call it via API Gateway

0

Hello,

I am trying to create a serverless API using Terraform with Lambda and API GTW. My lambda function needs to call a DynamoDB table and return a key-value pair, such as :

{ "Item": { "id": "visitors", "number": 33 },

To return this value, I am sending a payload dictionary with a POST to trigger the lambda.

The payload { "operation": "read", "payload": { "Key": { "id": "visitors" } } }

The first time I made the serverless API via the console, it worked fine. When I created with TF, I was using AWS proxy integration. People in this forum suggested that I change my code to the following, but it still doesn't work.

My function

import boto3
import json

table_name = "count-table"
dynamo = boto3.resource('dynamodb').Table(table_name)

def read(payload):
    return dynamo.get_item(Key=payload['Key'])

operations = {'read': read}

def lambda_handler(event, context):
    try:
        operation = event['operation']
        payload = event['payload']
        
        if operation in operations:
            result = operations[operation](payload)
            return {
                'statusCode': 200,
                'headers': {
                    'Content-Type': 'application/json'
                },
                'body': json.dumps(result)
            }
    except Exception as e:
        return {
            'statusCode': 500,
            'headers': {
                'Content-Type': 'application/json'
            },
            'body': json.dumps({'error': str(e)})
        }

Terraform Lambda integration

resource "aws_api_gateway_integration" "integration_get" {
  rest_api_id             = aws_api_gateway_rest_api.test_api.id
  resource_id             = aws_api_gateway_resource.test.id
  http_method             = aws_api_gateway_method.post_get.http_method
  integration_http_method = "POST"
  type                    = "AWS_PROXY"
  uri                     = aws_lambda_function.get_visits.invoke_arn
}

I tested Lambda isolated using the payload above and received the error "Object of type Decimal is not JSON serializable".

So I tried using import simplejson as json and returned this Response: { "statusCode": 200, "headers": { "Content-Type": "application/json" }, "body": "{"Item": {"id": "visitors", "number": 1}, "ResponseMetadata": {"RequestId": "GKNC3ETVJ63HNJED3SVTJNKG53VV4KQNSO5AEMVJF66Q9ASUAAJG", "HTTPStatusCode": 200, "HTTPHeaders": {"server": "Server", "date": "Tue, 03 Jun 2025 20:53:17 GMT", "content-type": "application/x-amz-json-1.0", "content-length": "51", "connection": "keep-alive", "x-amzn-requestid": "GKNC3ETVJ63HNJED3SVTJNKG53VV4KQNSO5AEMVJF66Q9ASUAAJG", "x-amz-crc32": "3824588171"}, "RetryAttempts": 0}}" } But testing from the API Gateway shows this error: Tue Jun 03 20:54:41 UTC 2025 : Endpoint response body before transformations: {"statusCode": 500, "headers": {"Content-Type": "application/json"}, "body": "{"error": "'operation'"}"} Tue Jun 03 20:54:41 UTC 2025 : Method response body after transformations: {"error": "'operation'"}

I appreciate any help. I've been stuck for a while now.

2 Answers
0
Accepted Answer

The issue you're experiencing is related to how API Gateway processes the request and passes it to your Lambda function. When using AWS_PROXY integration, API Gateway structures the event object differently than when testing directly in the Lambda console.

The error "'operation'" suggests that your Lambda function is trying to access the 'operation' key in the event object, but it doesn't exist in the structure that API Gateway is sending. With AWS_PROXY integration, your request body is actually nested inside event.body as a string, not directly accessible as event['operation'].

Here's how you can modify your Lambda function to handle requests coming from API Gateway:

import boto3
import json

table_name = "count-table"
dynamo = boto3.resource('dynamodb').Table(table_name)

def read(payload):
return dynamo.get_item(Key=payload['Key'])

operations = {'read': read}

def lambda_handler(event, context):
try:
# Check if the request is coming from API Gateway
if 'body' in event and isinstance(event['body'], str):
# Parse the body from API Gateway
body = json.loads(event['body'])
operation = body['operation']
payload = body['payload']
else:
# Direct Lambda invocation
operation = event['operation']
payload = event['payload']

if operation in operations:
result = operations[operation](payload)

# Handle Decimal serialization issue
return {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json'
},
'body': json.dumps(result, default=str)  # Use default=str to handle Decimal
}
else:
return {
'statusCode': 400,
'headers': {
'Content-Type': 'application/json'
},
'body': json.dumps({'error': f'Unrecognized operation "{operation}"'})
}
except Exception as e:
return {
'statusCode': 500,
'headers': {
'Content-Type': 'application/json'
},
'body': json.dumps({'error': str(e)})
}

Key changes:

  1. Added logic to check if the request is coming from API Gateway (event has a 'body' key with a string value)
  2. Used default=str in json.dumps() to handle the Decimal serialization issue from DynamoDB
  3. Added proper error handling for unrecognized operations

This should allow your function to work both when tested directly in the Lambda console and when called through API Gateway.

Also, make sure your API Gateway has the necessary permissions to invoke your Lambda function. You can check this in the Permissions tab of the Lambda console.
Sources
API Gateway fails to get a proper response body from my Lambda function | AWS re:Post
How Does API Gateway Handle the Response Returned by a Lambda Function? | AWS re:Post
Troubleshooting issues with HTTP API Lambda integrations - Amazon API Gateway
Api gatway with Lambda function | AWS re:Post

answered a year ago

AWS
SUPPORT ENGINEER

reviewed a year ago

0

It worked! Thank you!

answered a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.