Search code examples
aws-lambdapostmanaws-api-gatewayinsomnia

I can't pass JSON to an AWS lambda function in a POST request without the lambda function inserting a backslash before every double quote in the JSON


I have an AWS lambda function that I created through the sam cli tool. I started with a basic hello world template that I converted into a find anagrams function that accepts a JSON array of words and detects anagrams in the array. Right now, I'm just passing through the JSON input for debugging purposes. The template.yaml file looks like this:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  lambda-tester-two

  Sample SAM Template for lambda-tester-two
  
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3
    MemorySize: 128

Resources:
  HttpApi:
      Type: AWS::Serverless::HttpApi
      Properties:
        StageName: nonprod
  FindAnagramsFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: find-anagrams/
      Handler: app.lambdaHandler
      Runtime: nodejs16.x
      Architectures:
        - x86_64
      Events:
        PostWords:
          Type: HttpApi 
          Properties:
            Path: /anagram
            Method: post
            ApiId:
              Ref: HttpApi
    Metadata: # Manage esbuild properties
      BuildMethod: esbuild
      BuildProperties:
        Minify: true
        Target: "es2020"
        # Sourcemap: true # Enabling source maps will create the required NODE_OPTIONS environment variables on your lambda function during sam build
        EntryPoints: 
        - app.ts

The app.ts file looks like this:

import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';

/**
 *
 * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
 * @param {Object} event - API Gateway Lambda Proxy Input Format
 *
 * Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
 * @returns {Object} object - API Gateway Lambda Proxy Output Format
 *
 */

export const lambdaHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
    let response: APIGatewayProxyResult;
    try {
        const words = event.body;
        let result = {}
        
        for (const word of words) {
            const sorted = word.split("").sort().join("");
        
            if (sorted in result) {
                result[sorted].push(word);
            } else {
                result[sorted] = [word];
            }
        }
        response = {
            statusCode: 200,
            body: JSON.stringify({
                message: words,
            }),
        };
    } catch (err: unknown) {
        console.error(err);
        response = {
            statusCode: 500,
            body: JSON.stringify({
                message: err instanceof Error ? err.message : 'some error happened',
            }),
        };
    }

    return response;
};

I run the code with sam build then sam local start-api. I always have Docker Desktop running in the background. I expect this running code to accept a POST request at http://127.0.0.1:3000/anagram and print out the json sent in the body of the request. But the JSON that is returned looks weird... This is what my Insomnia window looks like:
enter image description here

Why is it adding all the \n \ characters before the " characters?

I tried making the input just a minified string with no spaces but it still returned weird...
enter image description here

Finally I added this code to replace const words = event.body; in order to strip out the \ characters:

const wordsWithSlashes = event.body;
const words = wordsWithSlashes.replace(/\\/g,"-");

And it ignored my regex and still returned weird JSON with \s before the " characters:
enter image description here

So how do I get my AWS lambda function to accept the correct JSON sent in the body of the request without adding \ characters?


Solution

  • The problem was actually in the response code with JSON.stringify(... First, let me post the entire fixed app.ts file:

    import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
    
    /**
     *
     * Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format
     * @param {Object} event - API Gateway Lambda Proxy Input Format
     *
     * Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html
     * @returns {Object} object - API Gateway Lambda Proxy Output Format
     *
     */
    
    export const lambdaHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
        let response: APIGatewayProxyResult;
        try {
            const words = JSON.parse(event.body).listedwords;
            let result = {}
            
            /* for (const word of words) {
                const sorted = word.split("").sort().join("");
            
                if (sorted in result) {
                    result[sorted].push(word);
                } else {
                    result[sorted] = [word];
                }
            } */
            response = {
                statusCode: 200,
                body: words
            };
        } catch (err: unknown) {
            console.error(err);
            response = {
                statusCode: 500,
                body: JSON.stringify({
                    message: err instanceof Error ? err.message : 'some error happened',
                }),
            };
        }
    
        return response;
    };
    

    The notable change is this:

    response = {
        statusCode: 200,
        body: words
    };
    

    Notice I'm not putting JSON.stringify(words) in the response body, I'm just putting words in the response body. So this is what the function now returns:
    enter image description here

    It's also worth noting that you do have to actually parse the input JSON in the POST request body like I did with this line: const words = JSON.parse(event.body).listedwords;. The JSON is now formatted properly.