TheQ
TheQ

Reputation: 2019

How to call a GET method in android with aws api gateway?

so i have this lambda function which simply takes in a username as input, and goes to dynamoDB and grabs me the corresponding user in that table with all its attributes and logs it out. It works just fine, when i test in lambda. But, when i call the GET method through the sdk it doesn't work, and i dont understand why?

here is that function in lambda.

AWS.config.update(dynamoDBConfiguration);

var dynamodb = new AWS.DynamoDB.DocumentClient(); 
exports.handler = function(event, context, callback) 
{
    console.log('entered exports handler');
    console.log(JSON.stringify(event, null, '  '));

    var userTableName = "usersTable";

    var params = {
        TableName : userTableName,
        Key: {
            "username": event.username
        }
        // AttributesToGet: [
        // 'STRING_VALUE',
        //  /* more items */
        // ],
    };
    dynamodb.get(params, function(err, data)
        { if (err) {
                console.log(err);
                callback(err);
            } else {
                console.log('great success: %j',data);
                callback(null, data);
            }
        });
};

Now im trying to test this function in API getway so i can later deploy the sdk, but im having huge trouble figuring this out and hope you guys can help me out of what im missing!

Here is my GET method in my api enter image description here

Next, my method request. enter image description here

My integration request enter image description here

My method response

enter image description here

followed by my output model

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
        "username": {"type":"string"}
    },
    "title": "Output"
}

And my integration response enter image description here

And here is the output i get when i test in Lambda (so works fine).

{
  "Item": {
    "experience": "0",
    "displayName": "Archer",
    "profileImageRef": "default",
    "folders": {
      "My Cards": {
        "cards": {},
        "name": "My Cards"
      }
    },
    "birthdate": "1/1/1990",
    "lastName": "Farooqui",
    "username": "Archer",
    "email": "[email protected]",
    "firstName": "Qamar"
  }
}

In android, here is my sdk i generated to put into my android studio.

MyUserClient sdk

@com.amazonaws.mobileconnectors.apigateway.annotation.Service(endpoint = "https://ow2zhiry2b.execute-api.us-west-2.amazonaws.com/awsTest")

    public interface MyUserClient {


        /**
         * A generic invoker to invoke any API Gateway endpoint.
         * @param request
         * @return ApiResponse
         */
        com.amazonaws.mobileconnectors.apigateway.ApiResponse execute(com.amazonaws.mobileconnectors.apigateway.ApiRequest request);

        /**
         * 
         * 
         * @param username 
         * @return Output
         */
        @com.amazonaws.mobileconnectors.apigateway.annotation.Operation(path = "/", method = "GET")
        Output rootGet(
                @com.amazonaws.mobileconnectors.apigateway.annotation.Parameter(name = "username", location = "query")
                String username);
    }

Here is my out output class that was generated as well from the sdk

public class Output {
    @com.google.gson.annotations.SerializedName("username")
    private String username = null;

    /**
     * Gets username
     *
     * @return username
     **/
    public String getUsername() {
        return username;
    }

    /**
     * Sets the value of username.
     *
     * @param username the new value
     */
    public void setUsername(String username) {
        this.username = username;
    }

}

And finally, i try to implement the GEt method in an async task, but it keeps crashing on a log statement.

class gateWayAsyncTask extends AsyncTask<Void, Void, Void>
    {
        private String userName;
        public gateWayAsyncTask(String userName)
        {
            this.userName = userName;
        }
        @Override
        protected Void doInBackground(Void... params)
        {
            creatingUser = clientFactory.build(com.awsTest.clientsdk.MyUserClient.class);
            userName = creatingUser.rootGet("Archer").getUsername();
            return null;
            //clientFactory, and creatingUser variables are assigned in the parent class of this Async task don't worry.
        }
        @Override
        public void onPostExecute(Void var)
        {
            Log.d("gateway","gateway succeded!");
            Log.d("gateway",userName);
            Toast.makeText(getBaseContext(),userName,Toast.LENGTH_LONG).show();
        }
    }

And here is my stackTrace

12-27 12:42:48.929 29019-29019/com.daprlabs.aaron.swipedeck2 E/UncaughtException: java.lang.NullPointerException: println needs a message
                                                                                      at android.util.Log.println_native(Native Method)
                                                                                      at android.util.Log.d(Log.java:139)
                                                                                      at com.daprlabs.aaron.zivitApp.Cognito.LogInZivit$gateWayAsyncTask.onPostExecute(LogInZivit.java:313)
                                                                                      at com.daprlabs.aaron.zivitApp.Cognito.LogInZivit$gateWayAsyncTask.onPostExecute(LogInZivit.java:281)
                                                                                      at android.os.AsyncTask.finish(AsyncTask.java:651)
                                                                                      at android.os.AsyncTask.access$500(AsyncTask.java:180)
                                                                                      at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
                                                                                      at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                      at android.os.Looper.loop(Looper.java:148)
                                                                                      at android.app.ActivityThread.main(ActivityThread.java:5525)
                                                                                      at java.lang.reflect.Method.invoke(Native Method)
                                                                                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
                                                                                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
12-27 12:42:49.169 29019-29019/com.daprlabs.aaron.swipedeck2 E/AndroidRuntime: FATAL EXCEPTION: main
                                                                               Process: com.daprlabs.aaron.swipedeck2, PID: 29019
                                                                               java.lang.NullPointerException: println needs a message
                                                                                   at android.util.Log.println_native(Native Method)
                                                                                   at android.util.Log.d(Log.java:139)
                                                                                   at com.daprlabs.aaron.zivitApp.Cognito.LogInZivit$gateWayAsyncTask.onPostExecute(LogInZivit.java:313)
                                                                                   at com.daprlabs.aaron.zivitApp.Cognito.LogInZivit$gateWayAsyncTask.onPostExecute(LogInZivit.java:281)
                                                                                   at android.os.AsyncTask.finish(AsyncTask.java:651)
                                                                                   at android.os.AsyncTask.access$500(AsyncTask.java:180)
                                                                                   at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
                                                                                   at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                   at android.os.Looper.loop(Looper.java:148)
                                                                                   at android.app.ActivityThread.main(ActivityThread.java:5525)
                                                                                   at java.lang.reflect.Method.invoke(Native Method)
                                                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
                                                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
12-27 12:43:14.387 29295-29295/com.daprlabs.aaron.swipedeck2 D/gateway: gateway succeded!
12-27 12:43:14.388 29295-29295/com.daprlabs.aaron.swipedeck2 E/UncaughtException: java.lang.NullPointerException: println needs a message
                                                                                      at android.util.Log.println_native(Native Method)
                                                                                      at android.util.Log.d(Log.java:139)
                                                                                      at com.daprlabs.aaron.zivitApp.Cognito.LogInZivit$gateWayAsyncTask.onPostExecute(LogInZivit.java:313)
                                                                                      at com.daprlabs.aaron.zivitApp.Cognito.LogInZivit$gateWayAsyncTask.onPostExecute(LogInZivit.java:281)
                                                                                      at android.os.AsyncTask.finish(AsyncTask.java:651)
                                                                                      at android.os.AsyncTask.access$500(AsyncTask.java:180)
                                                                                      at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
                                                                                      at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                      at android.os.Looper.loop(Looper.java:148)
                                                                                      at android.app.ActivityThread.main(ActivityThread.java:5525)
                                                                                      at java.lang.reflect.Method.invoke(Native Method)
                                                                                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
                                                                                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
12-27 12:43:14.604 29295-29295/com.daprlabs.aaron.swipedeck2 E/AndroidRuntime: FATAL EXCEPTION: main
                                                                               Process: com.daprlabs.aaron.swipedeck2, PID: 29295
                                                                               java.lang.NullPointerException: println needs a message
                                                                                   at android.util.Log.println_native(Native Method)
                                                                                   at android.util.Log.d(Log.java:139)
                                                                                   at com.daprlabs.aaron.zivitApp.Cognito.LogInZivit$gateWayAsyncTask.onPostExecute(LogInZivit.java:313)
                                                                                   at com.daprlabs.aaron.zivitApp.Cognito.LogInZivit$gateWayAsyncTask.onPostExecute(LogInZivit.java:281)
                                                                                   at android.os.AsyncTask.finish(AsyncTask.java:651)
                                                                                   at android.os.AsyncTask.access$500(AsyncTask.java:180)
                                                                                   at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
                                                                                   at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                   at android.os.Looper.loop(Looper.java:148)
                                                                                   at android.app.ActivityThread.main(ActivityThread.java:5525)
                                                                                   at java.lang.reflect.Method.invoke(Native Method)
                                                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
                                                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)

UPDATE

So when i looked at cloud watch. It does show that my lambda function is being called and executed. But, i am not getting a return value. So something is wrong with my method response and/or integration response, but i am not sure what.

Upvotes: 1

Views: 2839

Answers (2)

TheQ
TheQ

Reputation: 2019

So i solved the problem. Thanks to : @MikeD at AWS

If anyone wants to go from ANDROID -> API GATEWAY -> LAMBDA FUNCTION (end point,return a value) -> API GATEWAY -> ANDROID.

  1. Make sure your lambda function returns something (a string or a number).

So heres a simple calculator lambda function:

console.log('Loading the Calc function');

exports.handler = function(event, context) {
    console.log('Received event:', JSON.stringify(event, null, 2));
    if (event.a === undefined || event.b === undefined || event.op === undefined) {
        context.fail("400 Invalid Input");
    }
    var res = {};
    res.a = Number(event.a);
    res.b = Number(event.b);
    res.op = event.op;

    if (isNaN(event.a) || isNaN(event.b)) {
        context.fail("400 Invalid Operand");
    }

    switch(event.op)
    {
        case "+":
        case "add":
            res.c = res.a + res.b;
            console.log('WORKED FROM ANDROID!');
            break;
        case "-":
        case "sub":
            res.c = res.a - res.b;
            break;
        case "*":
        case "mul":
            res.c = res.a * res.b;
            break;
        case "/":
        case "div":
            res.c = res.b===0 ? NaN : Number(event.a) / Number(event.b);
            break;
        default:
            context.fail("400 Invalid Operator");
            break;
    }
    context.succeed(res);
};

Note that the variable name that i returned was res. Which contains 3 numbers a,b, and c.

Now if you're going back from Lambda -> API gateway -> Android. In your integration response, in body mapping templates, in application/json I have the following template:

#set($allParams = $input.params())
{
    "c" : $input.json('$.c')


}

Next, in your method response. Make sure you create a model (you can create models for your methods on the left side pane if you click on "models") for your method response and set it. Here is my output model:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
        "c": {"type":"string"}
    },
    "title": "Output"
}

I put this model in method response (repeating). AND notice how i have both c in my model (in method response) AND in my body mapping template in my integration response. You can put: "c": {"type":"number"} if you wanted.

Then when you deploy your api. It should work (if you're error was coming from the path: Lambda -> Api gateway -> Android).

Upvotes: 1

MikeD at AWS
MikeD at AWS

Reputation: 3745

It looks like your template in the integration response is empty and the Lambda output does not match your output model. On the integration response page, under Body Mapping Templates, select application/json on the left hand side. On the right hand side, enter a template body like this:


    {
        "username": $input.json('$.username')
    }

Also, try testing your API Gateway GET method via the test execute on the API Gateway console. If you're still having trouble, post the "Logs" output from the test invoke.

Upvotes: 1

Related Questions