Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Java on AWS Using Lambda, API Gateway, and CloudFormation

DZone's Guide to

Java on AWS Using Lambda, API Gateway, and CloudFormation

A practical example demonstrating integration between Java Lambda functions and API Gateway

· Cloud Zone
Free Resource

MongoDB Atlas is a database as a service that makes it easy to deploy, manage, and scale MongoDB. So you can focus on innovation, not operations. Brought to you in partnership with MongoDB.

In a previous post, we implemented a Java-based AWS Lambda function and deployed it using CloudFormation.

Now that we have our Lambda function set up, we will integrate it with an HTTP endpoint using AWS API Gateway.

Amazon API Gateway is a fully managed service that makes it easy for developers to create, publish, maintain, monitor, and secure APIs at any scale. With a few clicks in the AWS Management Console, you can create an API that acts as a “front door” for applications to access data, business logic, or functionality from your back-end services, such as workloads running on Amazon Elastic Compute Cloud (Amazon EC2), code running on AWS Lambda, or any Web application

For this example, imagine that API Gateway is an HTTP connector.

We will change our original function in order to implement a division.

package com.gkatzioura.deployment.lambda;

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

import java.math.BigDecimal;
import java.util.Map;
import java.util.logging.Logger;

/**
 * Created by gkatzioura on 9/10/2016.
 */
public class RequestFunctionHandler implements RequestHandler<Map<String,String>,String> {

    private static final String NUMERATOR_KEY = "numerator";
    private static final String DENOMINATOR_KEY = "denominator";

    private static final Logger LOGGER = Logger.getLogger(RequestFunctionHandler.class.getName());

    public String handleRequest(Map <String,String> values, Context context) {

        LOGGER.info("Handling request");

        if(!values.containsKey(NUMERATOR_KEY)||!values.containsKey(DENOMINATOR_KEY)) {
            return "You need both numberator and denominator";
        }

        try {
            BigDecimal numerator = new BigDecimal(values.get(NUMERATOR_KEY));
            BigDecimal denominator= new BigDecimal(values.get(DENOMINATOR_KEY));
            return  numerator.divide(denominator).toString();
        } catch (Exception e) {
            return "Please provide valid values";
        }
    }

}

Then, we will change our Lambda code and update it on S3.

aws s3 cp build/distributions/JavaLambdaDeployment.zip s3://lambda-functions/JavaLambdaDeployment.zip

Next, we update our CloudFormation template and add the API Gateway forwarding requests to our Lambda function.

First, we have to declare our REST API.

    "AGRA16PAA": {
      "Type": "AWS::ApiGateway::RestApi",
      "Properties": {"Name": "CalculationApi"}
    }

Then, we need to add a REST resource. Inside the DependsOn element, we can see the id of our REST API. Therefore, CloudWatch will create the resource after the REST API has been created.

"AGR2JDQ8": {
      "Type": "AWS::ApiGateway::Resource",
      "Properties": {
        "RestApiId": {"Ref": "AGRA16PAA"},
        "ParentId": {
          "Fn::GetAtt": ["AGRA16PAA","RootResourceId"]
        },
        "PathPart": "divide"
      },
      "DependsOn": [
        "AGRA16PAA"
      ]
    }

Another crucial part is to add a permission in order to be able to invoke our Lambda function.

    "LPI6K5": {
      "Type": "AWS::Lambda::Permission",
      "Properties": {
        "Action": "lambda:invokeFunction",
        "FunctionName": {"Fn::GetAtt": ["LF9MBL", "Arn"]},
        "Principal": "apigateway.amazonaws.com",
        "SourceArn": {"Fn::Join": ["",
          ["arn:aws:execute-api:", {"Ref": "AWS::Region"}, ":", {"Ref": "AWS::AccountId"}, ":", {"Ref": "AGRA16PAA"}, "/*"]
        ]}
      }
    }

The last step would be to add the API gateway method in order to be able to invoke our Lambda function from the API Gateway. Furthermore, we will add an API Gateway deployment instruction.

"Deployment": {
      "Type": "AWS::ApiGateway::Deployment",
      "Properties": {
        "RestApiId": { "Ref": "AGRA16PAA" },
        "Description": "First Deployment",
        "StageName": "StagingStage"
      },
      "DependsOn" : ["AGM25KFD"]
    },
    "AGM25KFD": {
      "Type": "AWS::ApiGateway::Method",
      "Properties": {
        "AuthorizationType": "NONE",
        "HttpMethod": "POST",
        "ResourceId": {"Ref": "AGR2JDQ8"},
        "RestApiId": {"Ref": "AGRA16PAA"},
        "Integration": {
          "Type": "AWS",
          "IntegrationHttpMethod": "POST",
          "IntegrationResponses": [{"StatusCode": 200}],
          "Uri": {
            "Fn::Join": [
              "",
              [
                "arn:aws:apigateway:",
                {"Ref": "AWS::Region"},
                ":lambda:path/2015-03-31/functions/",
                {"Fn::GetAtt": ["LF9MBL", "Arn"]},
                "/invocations"
              ]
            ]
          }
        },
        "MethodResponses": [{
          "StatusCode": 200
        }]
      }

So, we ended up with our new CloudWatch configuration.

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "LF9MBL": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Code": {
          "S3Bucket": "lambda-functions",
          "S3Key": "JavaLambdaDeployment.zip"
        },
        "FunctionName": "SimpleRequest",
        "Handler": "com.gkatzioura.deployment.lambda.RequestFunctionHandler",
        "MemorySize": 128,
        "Role": "arn:aws:iam::274402012893:role/lambda_basic_execution",
        "Runtime": "java8"
      }
    },
    "Deployment": {
      "Type": "AWS::ApiGateway::Deployment",
      "Properties": {
        "RestApiId": { "Ref": "AGRA16PAA" },
        "Description": "First Deployment",
        "StageName": "StagingStage"
      },
      "DependsOn" : ["AGM25KFD"]
    },
    "AGM25KFD": {
      "Type": "AWS::ApiGateway::Method",
      "Properties": {
        "AuthorizationType": "NONE",
        "HttpMethod": "POST",
        "ResourceId": {"Ref": "AGR2JDQ8"},
        "RestApiId": {"Ref": "AGRA16PAA"},
        "Integration": {
          "Type": "AWS",
          "IntegrationHttpMethod": "POST",
          "IntegrationResponses": [{"StatusCode": 200}],
          "Uri": {
            "Fn::Join": [
              "",
              [
                "arn:aws:apigateway:",
                {"Ref": "AWS::Region"},
                ":lambda:path/2015-03-31/functions/",
                {"Fn::GetAtt": ["LF9MBL","Arn"]},
                "/invocations"
              ]
            ]
          }
        },
        "MethodResponses": [{"StatusCode": 200}]
      },
      "DependsOn": ["LF9MBL","AGR2JDQ8","LPI6K5"]
    },
    "AGR2JDQ8": {
      "Type": "AWS::ApiGateway::Resource",
      "Properties": {
        "RestApiId": {"Ref": "AGRA16PAA"},
        "ParentId": {
          "Fn::GetAtt": ["AGRA16PAA","RootResourceId"]
        },
        "PathPart": "divide"
      },
      "DependsOn": ["AGRA16PAA"]
    },
    "AGRA16PAA": {
      "Type": "AWS::ApiGateway::RestApi",
      "Properties": {
        "Name": "CalculationApi"
      }
    },
    "LPI6K5": {
      "Type": "AWS::Lambda::Permission",
      "Properties": {
        "Action": "lambda:invokeFunction",
        "FunctionName": {"Fn::GetAtt": ["LF9MBL", "Arn"]},
        "Principal": "apigateway.amazonaws.com",
        "SourceArn": {"Fn::Join": ["",
          ["arn:aws:execute-api:", {"Ref": "AWS::Region"}, ":", {"Ref": "AWS::AccountId"}, ":", {"Ref": "AGRA16PAA"}, "/*"]
        ]}
      }
    }
 }
}

Last but not least, we have to update our previous CloudFormation stack.

So, we uploaded our latest template:

aws s3 cp cloudformationjavalambda2.template s3://cloudformation-templates/cloudformationjavalambda2.template

And all we have to do is to update our stack:

aws cloudformation update-stack --stack-name JavaLambdaStack --template-url https://s3.amazonaws.com/cloudformation-templates/cloudformationjavalambda2.template

Our stack has just been updated.

We can get to our API Gateway endpoint and try to issue a post.

curl -H "Content-Type: application/json" -X POST -d '{"numerator":1,"denominator":"2"}' https://{you api gateway endpoint}/StagingStage/divide
"0.5"

You can find the source code on GitHub.

MongoDB Atlas is the best way to run MongoDB on AWS — highly secure by default, highly available, and fully elastic. Get started free. Brought to you in partnership with MongoDB.

Topics:
aws lambda ,api gateway ,cloud ,java

Published at DZone with permission of Emmanouil Gkatziouras, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}