aws / aws-lambda-java-libs

Official mirror for interface definitions and helper classes for Java code running on the AWS Lambda platform.
https://aws.amazon.com/lambda/
Apache License 2.0
515 stars 231 forks source link

Lambda configure with SAM to read JSON from request body does not work #100

Open abhinav-jain09 opened 4 years ago

abhinav-jain09 commented 4 years ago

Description

Lambda configure with SAM to read JSON from request body does not work

Briefly describe the bug you are facing.

Steps to reproduce

I tried to develop a simple API where the request is in the form of simple JSON

"{\"test\": \"hello world\"}"

I wrote a sam template as follows

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-app

  Sample SAM Template for sam-app

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 20

Resources:
  HelloWorldFunction:
    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: HelloWorldFunction
      Handler: helloworld.App::handleRequest
      Runtime: java8
      MemorySize: 512
      Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
        Variables:
          PARAM1: VALUE
      Events:
        HelloWorld:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /{proxy+}
            Method: POST
            RestApiId: !Ref HelloWorldApi
            RequestModel: 
              Model: RequestClass # REQUIRED; must match the name of a model defined in the Models property of the AWS::Serverless::API
              Required: true # OPTIONAL; boolean

 HelloWorldApi:
      Name: HelloWorldFunctionApiGateway
      Type: AWS::Serverless::Api
      Properties:
        StageName : dev
        Models:
         RequestClass :
           {
      "$schema": "http://json-schema.org/draft-04/schema#",
      "title": "RequestClass",
      "type": "object",
      "properties": {
                      "test": { "type": "string" }} }          

Outputs:
  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
  # Find out more about other implicit resources you can reference within SAM
  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

then I used the event.json as

sam local invoke HelloWorldFunction --event events/event.json

{
    "body": "{\"test\": \"hello world\"}",
    "resource": "/{proxy+}",
    "path": "/hello",
    "httpMethod": "post",
    "isBase64Encoded": false,
    "queryStringParameters": {
      "foo": "bar"
    },
    "pathParameters": {
      "proxy": "/path/to/resource"
    },
    "stageVariables": {
      "baz": "qux"
    },
    "headers": {
      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
      "Accept-Encoding": "gzip, deflate, sdch",
      "Accept-Language": "en-US,en;q=0.8",
      "Cache-Control": "max-age=0",
      "CloudFront-Forwarded-Proto": "https",
      "CloudFront-Is-Desktop-Viewer": "true",
      "CloudFront-Is-Mobile-Viewer": "false",
      "CloudFront-Is-SmartTV-Viewer": "false",
      "CloudFront-Is-Tablet-Viewer": "false",
      "CloudFront-Viewer-Country": "US",
      "Host": "1234567890.execute-api.us-east-1.amazonaws.com",
      "Upgrade-Insecure-Requests": "1",
      "User-Agent": "Custom User Agent String",
      "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",
      "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",
      "X-Forwarded-For": "127.0.0.1, 127.0.0.2",
      "X-Forwarded-Port": "443",
      "X-Forwarded-Proto": "https"
    },
    "requestContext": {
      "accountId": "123456789012",
      "resourceId": "123456",
      "stage": "prod",
      "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
      "requestTime": "09/Apr/2015:12:34:56 +0000",
      "requestTimeEpoch": 1428582896000,
      "identity": {
        "cognitoIdentityPoolId": null,
        "accountId": null,
        "cognitoIdentityId": null,
        "caller": null,
        "accessKey": null,
        "sourceIp": "127.0.0.1",
        "cognitoAuthenticationType": null,
        "cognitoAuthenticationProvider": null,
        "userArn": null,
        "userAgent": "Custom User Agent String",
        "user": null
      },
      "path": "/prod/path/to/resource",
      "resourcePath": "/{proxy+}",
      "httpMethod": "POST",
      "apiId": "1234567890",
      "protocol": "HTTP/1.1"
    }
  }

Handler is as follows


package helloworld;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

/**
 * Handler for requests to Lambda function.
 */
public class App  implements RequestHandler<RequestClass,Object> {

    public Object handleRequest(RequestClass input, Context context) {

        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put("X-Custom-Header", "application/json");
**Output of the follwoing line  always null** 
      System.out.println(input.getTest());
        try {
            final String pageContents = this.getPageContents("https://checkip.amazonaws.com");
            String output = String.format(input.toString(), pageContents);
            return new GatewayResponse(output, headers, 200);
        } catch (IOException e) {
            return new GatewayResponse("{}", headers, 500);
        }
    }

    private String getPageContents(String address) throws IOException{
        URL url = new URL(address);
        try(BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {
            return br.lines().collect(Collectors.joining(System.lineSeparator()));
        }
    }
}

Request class is follows

package helloworld;

public class RequestClass {
    public String test;

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }

    @Override
    public String toString() {
        return "HelloWorld{" +
                "test='" + test + '\'' +
                '}';
    }

    public RequestClass() {
    }
}

Observed result

The value of system out should be "Test" but its printing "null" meaning the RequestClass is not mapped with the incoming JSON. This is supported in AWS lambda as follows https://docs.aws.amazon.com/lambda/latest/dg/java-handler-io-type-pojo.html

Please provide command output with --debug flag set.

Expected result

Should be able to map JSON to the java POJO object

Describe what you expected.

Additional environment details (Ex: Windows, Mac, Amazon Linux etc)

  1. OS:MAC OS
  2. sam --version:SAM CLI, version 0.22.0

Add --debug flag to command you are running

t12344 commented 2 years ago

Description

Lambda configure with SAM to read JSON from request body does not work

Briefly describe the bug you are facing.

Steps to reproduce

I tried to develop a simple API where the request is in the form of simple JSON

"{\"test\": \"hello world\"}"

I wrote a sam template as follows


AWSTemplateFormatVersion: '2010-09-09'

Transform: AWS::Serverless-2016-10-31

Description: >

  sam-app

  Sample SAM Template for sam-app

# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst

Globals:

  Function:

    Timeout: 20

Resources:

  HelloWorldFunction:

    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: HelloWorldFunction

      Handler: helloworld.App::handleRequest

      Runtime: java8

      MemorySize: 512

      Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object

        Variables:

          PARAM1: VALUE

      Events:

        HelloWorld:

          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api

          Properties:

            Path: /{proxy+}

            Method: POST

            RestApiId: !Ref HelloWorldApi

            RequestModel: 

              Model: RequestClass # REQUIRED; must match the name of a model defined in the Models property of the AWS::Serverless::API

              Required: true # OPTIONAL; boolean

 HelloWorldApi:

      Name: HelloWorldFunctionApiGateway

      Type: AWS::Serverless::Api

      Properties:

        StageName : dev

        Models:

         RequestClass :

           {

      "$schema": "http://json-schema.org/draft-04/schema#",

      "title": "RequestClass",

      "type": "object",

      "properties": {

                      "test": { "type": "string" }} }          

Outputs:

  # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function

  # Find out more about other implicit resources you can reference within SAM

  # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api

  HelloWorldApi:

    Description: "API Gateway endpoint URL for Prod stage for Hello World function"

    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"

  HelloWorldFunction:

    Description: "Hello World Lambda Function ARN"

    Value: !GetAtt HelloWorldFunction.Arn

  HelloWorldFunctionIamRole:

    Description: "Implicit IAM Role created for Hello World function"

    Value: !GetAtt HelloWorldFunctionRole.Arn

then I used the event.json as

sam local invoke HelloWorldFunction --event events/event.json


{

    "body": "{\"test\": \"hello world\"}",

    "resource": "/{proxy+}",

    "path": "/hello",

    "httpMethod": "post",

    "isBase64Encoded": false,

    "queryStringParameters": {

      "foo": "bar"

    },

    "pathParameters": {

      "proxy": "/path/to/resource"

    },

    "stageVariables": {

      "baz": "qux"

    },

    "headers": {

      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",

      "Accept-Encoding": "gzip, deflate, sdch",

      "Accept-Language": "en-US,en;q=0.8",

      "Cache-Control": "max-age=0",

      "CloudFront-Forwarded-Proto": "https",

      "CloudFront-Is-Desktop-Viewer": "true",

      "CloudFront-Is-Mobile-Viewer": "false",

      "CloudFront-Is-SmartTV-Viewer": "false",

      "CloudFront-Is-Tablet-Viewer": "false",

      "CloudFront-Viewer-Country": "US",

      "Host": "1234567890.execute-api.us-east-1.amazonaws.com",

      "Upgrade-Insecure-Requests": "1",

      "User-Agent": "Custom User Agent String",

      "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)",

      "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==",

      "X-Forwarded-For": "127.0.0.1, 127.0.0.2",

      "X-Forwarded-Port": "443",

      "X-Forwarded-Proto": "https"

    },

    "requestContext": {

      "accountId": "123456789012",

      "resourceId": "123456",

      "stage": "prod",

      "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",

      "requestTime": "09/Apr/2015:12:34:56 +0000",

      "requestTimeEpoch": 1428582896000,

      "identity": {

        "cognitoIdentityPoolId": null,

        "accountId": null,

        "cognitoIdentityId": null,

        "caller": null,

        "accessKey": null,

        "sourceIp": "127.0.0.1",

        "cognitoAuthenticationType": null,

        "cognitoAuthenticationProvider": null,

        "userArn": null,

        "userAgent": "Custom User Agent String",

        "user": null

      },

      "path": "/prod/path/to/resource",

      "resourcePath": "/{proxy+}",

      "httpMethod": "POST",

      "apiId": "1234567890",

      "protocol": "HTTP/1.1"

    }

  }

Handler is as follows


package helloworld;

import java.io.BufferedReader;

import java.io.InputStreamReader;

import java.io.IOException;

import java.net.URL;

import java.util.HashMap;

import java.util.Map;

import java.util.stream.Collectors;

import com.amazonaws.services.lambda.runtime.Context;

import com.amazonaws.services.lambda.runtime.RequestHandler;

/**

 * Handler for requests to Lambda function.

 */

public class App  implements RequestHandler<RequestClass,Object> {

    public Object handleRequest(RequestClass input, Context context) {

        Map<String, String> headers = new HashMap<>();

        headers.put("Content-Type", "application/json");

        headers.put("X-Custom-Header", "application/json");

**Output of the follwoing line  always null** 

      System.out.println(input.getTest());

        try {

            final String pageContents = this.getPageContents("https://checkip.amazonaws.com");

            String output = String.format(input.toString(), pageContents);

            return new GatewayResponse(output, headers, 200);

        } catch (IOException e) {

            return new GatewayResponse("{}", headers, 500);

        }

    }

    private String getPageContents(String address) throws IOException{

        URL url = new URL(address);

        try(BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {

            return br.lines().collect(Collectors.joining(System.lineSeparator()));

        }

    }

}

Request class is follows


package helloworld;

public class RequestClass {

    public String test;

    public String getTest() {

        return test;

    }

    public void setTest(String test) {

        this.test = test;

    }

    @Override

    public String toString() {

        return "HelloWorld{" +

                "test='" + test + '\'' +

                '}';

    }

    public RequestClass() {

    }

}

Observed result

The value of system out should be "Test" but its printing "null" meaning the RequestClass is not mapped with the incoming JSON.

This is supported in AWS lambda as follows

https://docs.aws.amazon.com/lambda/latest/dg/java-handler-io-type-pojo.html

Please provide command output with --debug flag set.

Expected result

Should be able to map JSON to the java POJO object

Describe what you expected.

Additional environment details (Ex: Windows, Mac, Amazon Linux etc)

  1. OS:MAC OS

  2. sam --version:SAM CLI, version 0.22.0

Add --debug flag to command you are running