├── .gitignore ├── README.md ├── build_and_deploy.sh ├── destroy.sh ├── helloworldjava ├── pom.xml └── src │ └── main │ └── java │ └── uk │ └── co │ └── danielbryant │ └── exp │ └── helloworld │ ├── HelloLambdaHandler.java │ ├── service │ └── HelloService.java │ └── view │ ├── Request.java │ └── Response.java └── terraform ├── gateway.tf ├── iam.tf ├── lambda.tf ├── main.tf ├── outputs.tf └── variables.tf /.gitignore: -------------------------------------------------------------------------------- 1 | terraform.tfvars 2 | **/.terraform 3 | *.tfstate* 4 | *.out 5 | 6 | *.iml 7 | .idea 8 | **/target 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aws-lambda-terraform-java 2 | 3 | This is a *very* simple demonstration of the code required to deploy a Java 4 | [AWS Lambda Function](https://aws.amazon.com/lambda/) and expose the function 5 | with [AWS API Gateway](https://aws.amazon.com/api-gateway/). The infrastructure 6 | configuration and deployment is executed using [HashiCorp's Terraform](https://www.terraform.io/) programmable infrastructure tool. 7 | 8 | ## Get started 9 | 10 | To get started simply create a ```terraform.tfvars``` file in ```terraform``` 11 | directory with your AWS account/IAM User details. Your IAM User must have 12 | [permissions](http://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html) 13 | for AWS Lambda and AWS API Gateway. 14 | 15 | The contents should follow the template below (with you replacing the info 16 | between ```<< >>```): 17 | 18 | ``` 19 | aws_access_key = "<< your IAM user AWS access key >>" 20 | aws_secret_key = "<< your IAM user AWS secret key >>" 21 | region = "<< your chosen region >>" 22 | account_id = "<>" 23 | 24 | ``` 25 | 26 | From the root of the project run the ```build_and_deploy.sh``` script. 27 | This compiles the Java application into the ```helloworld/target``` directory 28 | and runs Terraform to upload and configure the Lambda function and API Gateway. 29 | 30 | ``` 31 | $ ./build_and_deploy.sh 32 | ``` 33 | 34 | ## Manually test your function 35 | After a successful run, something similar to the output below should be visible: 36 | 37 | ``` 38 | Outputs: 39 | 40 | curl = curl -H 'Content-Type: application/json' -X POST -d '{"name": "Daniel"}' https://XXXXXXXXXX.execute-api.eu-west-1.amazonaws.com/beta/helloworld 41 | ``` 42 | To test your Lambda deployed behind the API Gateway all you need to do is 43 | copy/paste the curl command (minus the ```curl = ``` part) e.g. 44 | 45 | ``` 46 | curl -H 'Content-Type: application/json' -X POST -d '{"name": "Daniel"}' https://XXXXXXXXXX.execute-api.eu-west-1.amazonaws.com/beta/helloworld 47 | ``` 48 | 49 | ## Rinse and repeat 50 | You can make changes to the Java application and run the ```build_and_deploy.sh``` 51 | script repeatedly to update the Lambda Function deployed into AWS. 52 | 53 | ## Tidy up when finished! 54 | When you are finished, don't forget to shut your infrastructure down: 55 | 56 | ``` 57 | $ ./destroy.sh 58 | ``` 59 | 60 | ## Disclaimer 61 | Please note: I'm not responsible for any costs incurred within your AWS account :-) 62 | -------------------------------------------------------------------------------- /build_and_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd helloworldjava 4 | printf '\n\nBuilding the Java Lambda Function!\n\n' 5 | mvn clean verify 6 | if [ $? -ne 0 ]; then 7 | printf '\n\nJava application build failed! No new Lambda Function will be deployed!!!i\n' 8 | exit -1 9 | fi 10 | 11 | cd .. 12 | printf '\n\nStarting the Terraforming!\n\n' 13 | cd terraform 14 | terraform plan -out=plan.out 15 | terraform apply plan.out 16 | -------------------------------------------------------------------------------- /destroy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd terraform 4 | terraform destroy -force 5 | rm plan.out 6 | -------------------------------------------------------------------------------- /helloworldjava/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | uk.co.danielbryant.exp 8 | helloworldjava 9 | 0.1.0-SNAPSHOT 10 | 11 | 12 | 13 | com.amazonaws 14 | aws-lambda-java-core 15 | 1.1.0 16 | 17 | 18 | 19 | 20 | 21 | 22 | org.apache.maven.plugins 23 | maven-shade-plugin 24 | 2.3 25 | 26 | false 27 | 28 | 29 | 30 | package 31 | 32 | shade 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /helloworldjava/src/main/java/uk/co/danielbryant/exp/helloworld/HelloLambdaHandler.java: -------------------------------------------------------------------------------- 1 | package uk.co.danielbryant.exp.helloworld; 2 | 3 | 4 | import com.amazonaws.services.lambda.runtime.Context; 5 | import com.amazonaws.services.lambda.runtime.RequestHandler; 6 | import uk.co.danielbryant.exp.helloworld.service.HelloService; 7 | import uk.co.danielbryant.exp.helloworld.view.Request; 8 | import uk.co.danielbryant.exp.helloworld.view.Response; 9 | 10 | public class HelloLambdaHandler implements RequestHandler { 11 | 12 | private final HelloService helloService; 13 | 14 | public HelloLambdaHandler() { 15 | this.helloService = new HelloService(); 16 | } 17 | 18 | public Response handleRequest(Request request, Context context) { 19 | final String name = request.getName(); 20 | final String currentLocation = System.getenv("currentLocation"); 21 | 22 | final Response response = new Response(helloService.generateHello(name, currentLocation)); 23 | return response; 24 | } 25 | } -------------------------------------------------------------------------------- /helloworldjava/src/main/java/uk/co/danielbryant/exp/helloworld/service/HelloService.java: -------------------------------------------------------------------------------- 1 | package uk.co.danielbryant.exp.helloworld.service; 2 | 3 | public class HelloService { 4 | 5 | public String generateHello(final String name, final String currentLocation) { 6 | return String.format("Hello %s from %s", name, currentLocation); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /helloworldjava/src/main/java/uk/co/danielbryant/exp/helloworld/view/Request.java: -------------------------------------------------------------------------------- 1 | package uk.co.danielbryant.exp.helloworld.view; 2 | 3 | public class Request { 4 | 5 | private String name; 6 | 7 | public Request() { 8 | } 9 | 10 | public void setName(final String name) { 11 | this.name = name; 12 | } 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /helloworldjava/src/main/java/uk/co/danielbryant/exp/helloworld/view/Response.java: -------------------------------------------------------------------------------- 1 | package uk.co.danielbryant.exp.helloworld.view; 2 | 3 | public class Response { 4 | 5 | private String output; 6 | 7 | public Response(final String output) { 8 | this.output = output; 9 | } 10 | 11 | public String getOutput() { 12 | return output; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /terraform/gateway.tf: -------------------------------------------------------------------------------- 1 | resource "aws_api_gateway_rest_api" "hello_world_api" { 2 | name = "hello_world_api" 3 | description = "Hello, world API" 4 | } 5 | 6 | resource "aws_api_gateway_resource" "hello_world_api_gateway" { 7 | rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}" 8 | parent_id = "${aws_api_gateway_rest_api.hello_world_api.root_resource_id}" 9 | path_part = "${var.api_path}" 10 | } 11 | 12 | resource "aws_api_gateway_method" "hello_world_method" { 13 | rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}" 14 | resource_id = "${aws_api_gateway_resource.hello_world_api_gateway.id}" 15 | http_method = "${var.hello_world_http_method}" 16 | authorization = "NONE" 17 | } 18 | 19 | resource "aws_api_gateway_integration" "hello_world_integration" { 20 | rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}" 21 | resource_id = "${aws_api_gateway_resource.hello_world_api_gateway.id}" 22 | http_method = "${aws_api_gateway_method.hello_world_method.http_method}" 23 | integration_http_method = "${aws_api_gateway_method.hello_world_method.http_method}" 24 | type = "AWS" 25 | uri = "arn:aws:apigateway:${var.region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${var.region}:${var.account_id}:function:${aws_lambda_function.hello_world_function.function_name}/invocations" 26 | credentials = "arn:aws:iam::${var.account_id}:role/${aws_iam_role.lambda_apigateway_iam_role.name}" 27 | } 28 | 29 | resource "aws_api_gateway_method_response" "200" { 30 | rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}" 31 | resource_id = "${aws_api_gateway_resource.hello_world_api_gateway.id}" 32 | http_method = "${aws_api_gateway_method.hello_world_method.http_method}" 33 | 34 | response_models = { 35 | "application/json" = "Empty" 36 | } 37 | 38 | status_code = "200" 39 | } 40 | 41 | resource "aws_api_gateway_integration_response" "hello_world_integration_response" { 42 | depends_on = ["aws_api_gateway_integration.hello_world_integration"] 43 | rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}" 44 | resource_id = "${aws_api_gateway_resource.hello_world_api_gateway.id}" 45 | http_method = "${aws_api_gateway_method.hello_world_method.http_method}" 46 | status_code = "${aws_api_gateway_method_response.200.status_code}" 47 | } 48 | 49 | resource "aws_api_gateway_deployment" "hello_world_deploy" { 50 | depends_on = ["aws_api_gateway_integration.hello_world_integration"] 51 | stage_name = "${var.api_env_stage_name}" 52 | rest_api_id = "${aws_api_gateway_rest_api.hello_world_api.id}" 53 | } 54 | -------------------------------------------------------------------------------- /terraform/iam.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_role" "lambda_apigateway_iam_role" { 2 | name = "lambda_apigateway_iam_role" 3 | 4 | assume_role_policy = <