Why does Lambda URL convert the request body from JSON to string?

1

Hi there,

We are making use of the new Lambda URL feature. When we invoke the URL of our function to send a POST request with a simple body, what we see in the event that the function receives is that the body is shown as a string, and not as a JSON.

For a simple request body that looks like:

{
    "accountId": "123456789012",
    "duration": 5
}

this is what we see in the event object that is passed to the function upon invocation:

{
    "version": "2.0",
    "routeKey": "$default",
    "rawPath": "/",
    "rawQueryString": "",
    "headers": {
        "content-length": "55",
        "x-amz-date": "20220509T192924Z",
        "x-forwarded-proto": "https",
        "x-forwarded-port": "443",
        "x-forwarded-for": "OBFUSCATED",
        "x-amz-security-token": "OBFUSCATED",
        "accept": "*/*",
        "x-amzn-trace-id": "OBFUSCATED",
        "host": "OBFUSCATED",
        "content-type": "application/json",
        "accept-encoding": "gzip, deflate, br",
        "user-agent": "Thunder Client (https://www.thunderclient.com)"
    },
    "requestContext": {
        "accountId": "123456789012",
        "apiId": "OBFUSCATED",
        "authorizer": {
            "iam": {
                "accessKey": "OBFUSCATED",
                "accountId": "123456789012",
                "callerId": "OBFUSCATED",
                "cognitoIdentity": "None",
                "principalOrgId": "OBFUSCATED",
                "userArn": "arn:aws:sts::123456789012:assumed-role/ExampleRole",
                "userId": "OBFUSCATED"
            }
        },
        "domainName": "OBFUSCATED",
        "domainPrefix": "OBFUSCATED",
        "http": {
            "method": "POST",
            "path": "/",
            "protocol": "HTTP/1.1",
            "sourceIp": "OBFUSCATED",
            "userAgent": "Thunder Client (https://www.thunderclient.com)"
        },
        "requestId": "b76a957b-2f63-4fd8-8944-65hy79b62711",
        "routeKey": "$default",
        "stage": "$default",
        "time": "09/May/2022:19:29:28 +0000",
        "timeEpoch": 1652124568118
    },
    "body": "{\\n    \"accountId\": \"123456789012\",\\n    \"duration\": 5\\n}",
    "isBase64Encoded": "False"
}

As you can see the value of the body node is wrapped in " and AWS has added also the new line characters together with escape characters.

Because of this, we can't simply parse the body, and therefore we always have to deserialize it and remove the newline characters.

Any idea why this happens? Am I missing something when I send the request?

Thank you in advance!

Pier
asked 2 years ago8206 views
4 Answers
0
Accepted Answer

Hey Pier, you are right. My answer was wrong in your context, sorry about that. But the body being string is by design as noted by Uri.

profile pictureAWS
Eduardo
answered 2 years ago
0

This is by design.

I think you are only able to change it using API Gateway. Lambda functions with PROXY integration accelerates your integration process as you don't need to create the request and response templates. And, as the Lambda can receive binary payload in BASE64, the body should have a type for this case also, as, the payload is not JSON.

You can still receive the payload as JSON if you setup the request and response templates by yourself.

profile pictureAWS
Eduardo
answered 2 years ago
  • Thank you for your answer, Eduardo.

    How can set up a request template for a Lambda URL? I haven't seen that being supported for Lambda URLs. The link you posted is for API Gateway.

  • The reason provided by Eduardo is correct, although the details relate to API Gateway with Lambda and not Lambda Function URLs.

    I think that depending on the programming language, you should be able to parse it easily, e.g., in Python use something like body = json.loads(event.body)

0

When calling the function from outside, you'll get an event composed by the system, and in it, the body will be a string. If you want to use it as an object, you need to convert it back. For example, in node.js, you need to use something like this:

exports.handler = async (event) => {
  const body = JSON.parse(event.body)
...

ps. You may also want to prepare for errors in the body, as it may be invalid, so, you can put the parse in a try..catch block, and check if the required parameter is defined etc.

answered a year ago
0

I haven't found any documentation of this in the AWS Lambda documentation. It seems like a basic fundamental concern that should be addressed in AWS Lambda 101. Did I miss the documentation or do you have to trawl through user questions to get this information?

p.s. I've found some related documentation under AWS API Gateway, but I still don't see Lambda documentation of fundamental concerns such as parsing of the JSON body, HTTP status header control for responses, additional content that Lambda seems to generate in the response, etc.: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-integrations.html

Neil
answered 7 months 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.

Guidelines for Answering Questions