aws / aws-sam-cli

CLI tool to build, test, debug, and deploy Serverless applications using AWS SAM
https://aws.amazon.com/serverless/sam/
Apache License 2.0
6.51k stars 1.17k forks source link

aws lambda didn't convert json request to POJO #242

Closed JakimLi closed 6 years ago

JakimLi commented 6 years ago

I have a lambda function:

    package org.smarter.note;

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

    public class AddNoteRequestHandler implements RequestHandler<NewNoteRequest, Note> {

        private NoteRepository notes;
        private LambdaLogger logger;

        @Override
        public Note handleRequest(NewNoteRequest newNote, Context context) {
            init(context);

            log("creating note: " + newNote.toJson());

            notes.create(newNote);

            return new Note();
        }

        private void log(String message) {
            logger.log(String.format("%s\n", message));
        }

        private void init(Context context) {
            this.logger = context.getLogger();
            this.notes = new NoteRepository();
        }
    }

Then when I am testing the lambda using sam local, and send a request:

    {
        "title": "hello",
        "content": "body"
    }

I am expecting the json converted to NewNoteRequest automatically, but it didn't. here is the log:

    You can now browse to the above endpoints to invoke your functions.
    You do not need to restart/reload SAM CLI while working on your functions,
    changes will be reflected instantly/automatically. You only need to restart
    SAM CLI if you update your AWS SAM template.

    2017/12/28 11:06:57 Invoking org.smarter.note.AddNoteRequestHandler (java8)
    2017/12/28 11:06:57 Decompressing /Work/smarter-serverless/build/distributions/smarter-serverless.zip
    2017/12/28 11:06:57 Mounting /private/var/folders/gv/m43y5g9x1xdc9f2kc2p0kpz00000gp/T/aws-sam-local-1514430417742696978 as /var/task:ro inside runtime container
    START RequestId: bf0f77d3-198d-4211-ab9e-4c85a7c5de22 Version: $LATEST
    creating note: {title=null, content=null}

my sam local template:

    AWSTemplateFormatVersion : '2010-09-09'
    Transform: AWS::Serverless-2016-10-31

    Resources:
      notes:
        Type: AWS::Serverless::Function
        Properties:
          Handler: org.smarter.note.AddNoteRequestHandler
          CodeUri: ./build/distributions/smarter-serverless.zip
          Runtime: java8
          Events:
            PostEvent:
              Type: Api
              Properties:
                Path: /notes
                Method: post

The POJO:

    package org.smarter.note;

    import com.amazonaws.services.dynamodbv2.document.Item;

    import java.util.HashMap;
    import java.util.Map;

    class NewNoteRequest implements DynamoDBItem, Json {
        private String title;
        private String content;

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }

        @Override
        public Item item() {
            return new Item()
                    .withString("title", this.title)
                    .withString("content", this.content);
        }

        @Override
        public Map<String, Object> toJson() {
            HashMap<String, Object> json = new HashMap<String, Object>();
            json.put("title", this.title);
            json.put("content", this.content);
            return json;
        }
    }

Also the dependencies are:

    dependencies {
        compile(
                "com.amazonaws:aws-lambda-java-core:1.1.0",
                "com.amazonaws:aws-lambda-java-events:1.1.0"
        )
    }

I cannot figure out which part is wrong, AWS document says it can do the mapping directly. Please help.

mikkokupsu commented 6 years ago

I faced the same problem and there is a definately a bug here. The lambda function gets the content of the POST as JSON, not only the body. Below is what is passed to my test Lambda function. I would have assumed that just {'foo': 'bar'} would have been passed to the Lambda function.

/usr/bin/java 
-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,quiet=y,address=5005 
-XX:MaxHeapSize=1336935k 
-XX:MaxMetaspaceSize=157286k 
-XX:ReservedCodeCacheSize=78643k 
-XX:+UseSerialGC 
-XX:-TieredCompilation 
-jar /var/runtime/lib/LambdaJavaRTEntry-1.0.jar 
com.some.EchoHandler 
{"httpMethod":"POST","body":"{\"foo\":\"bar\"}","resource":"/echo","requestContext":{"resourcePath":"/echo","httpMethod":"POST","stage":"prod","identity":{"sourceIp":"127.0.0.1:58482"}},"queryStringParameters":{},"headers":{"Accept":"*/*","Content-Length":"55","Content-Type":"application/json","User-Agent":"curl/7.55.1"},"pathParameters":null,"stageVariables":null,"path":"/echo"}
sanathkr commented 6 years ago

SAM CLI doesn't do anything special to handle the JSON -> POJO conversion. It is done within the docker container which is a part of github.com/lambci/docker-lambda project