This pattern creates an Amazon API Gateway HTTP API, a AWS Lambda function and a DynamoDB Table using SAM and Java 11.
Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the AWS Pricing page for details. You are responsible for any AWS costs incurred.
This is a Maven project which uses Java 11 and AWS SDK
The framework used to deploy the infrastructure is SAM
The AWS services used in this pattern are
Topology
The SAM template contains all the information to deploy AWS resources(an API Gateway, a Lambda function and a DynamoDB table) and also the permission required by these service to communicate.
You will be able to create and delete the CloudFormation stack using the CLI commands.
After the stack is created you can send an JSON object using curl or Postman to the URL provided by the API Gateway, the request will be intercepted by the Lambda function which will persist the object into a DynamoDB table.
The lambda function will return the ID of the inserted object.
- Java 11
- Maven
- Create an AWS account if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
- AWS CLI installed and configured
- Git Installed
- AWS Serverless Application Model (AWS SAM) installed
# BUILD the project
sam build
# DEPLOY the stack to AWS
sam deploy --guided
# DELETE the stack
sam delete --stack-name <STACK_NAME>
To test the endpoint first send data using the following command. Be sure to update the endpoint with endpoint of your stack.
curl -X POST https://<API_GATEWAY_URL>/dev/ticket -H "Content-Type: application/json" -d '{"userId": "231deb432f3dd","description": "My monitor is broken."}'
The source code for this sample includes automated tests.
These tests are run while packaging the lambda function using mvn clean package
or can be run standalone using mvn test
.
Junit 5 is the primary test framework used to write these tests. A few other libraries and frameworks are used depending on the test case pattern. Please see below.
The sample includes the following tests:
Unit Test (TicketFunctionMockTest.java)
The goal of this test is to validate the handler method of the Lambda function independently of external dependencies (DynamoDB). It uses Mockito as a mocking framework. All the calls to the Amazon DynamoDB service are mocked using Mockito.
It also uses aws-lambda-java-test library. This library helps
to easily inject APIGatewayProxyRequestEvent
into the Lambda function's handler method. To know more about how to leverage aws-lambda-java-test
you can refer to this blog.
Local Test using containers (TicketFunctionContainerTest.java)
This test is an extension of the previous one, except that we don't rely on a Java mocking framework but on a mock of the cloud environment. We use localstack to simulate AWS services locally. This test uses containers and requires Docker installed locally.
Integration Test (TicketFunctionIntegrationTest.java)
The goal of this test is to validate the Lambda function code without mocking any calls to the Amazon DynamoDB service. It assumes that the DynamoDB table is provisioned in your AWS account (using sam deploy
) and you have the appropriate credentials locally to access this account (for example in ~/.aws/credentials).
End-to-End Test (TicketEnd2EndTest.java)
The goal of this test is to validate the whole application end-to-end on AWS, to ensure API Gateway / Lambda / DynamoDB are correctly configured (ARNs, permissions) and communicate properly together. This test assumes the application stack provided in the sample is deployed to AWS. The stack name is referred in the test class as a String constant.
private static final String STACK_NAME = "APIGW-Lambda-DDB-Sample";
Please make sure to replace the above with your stack name. This test submits an HTTP request to the API Gateway endpoint and verifies that the results are reflected in the DynamoDB database table.
Load Test (using Artillery)
Load tests should be executed in the cloud prior to any initial deployment to production environments. Load tests can be useful to discover performance bottlenecks and quota limits. Load tests should simulate your application's expected peak load + 10% or more.
There are several tools available for serverless developers to perform load testing. One of the most popular is Artillery Community Edition
, which is an open-source tool for testing serverless APIs. You configure the number of requests per second and overall test duration, and it uses a headless Chromium browser to run its test flows.
This project uses an open source performance testing tool called Serverless Artillery
.
The load test in this repo assumes the application stack provided in this sample is deployed using sam build and deploy on AWS as we need the endpoint details form the deployed api to run our load test against.
Steps:
-
Install Artillery library
npm install artillery@latest
-
Install Faker library (Optional. Only required to run sample load tests in this repo. Not a requirement to use Artillery library)
npm install faker
-
Review
load-test/load-test-static-data.yml
, which is the config file to show how to use pre-defined test data from a csv file to run your tests against, whereasload-test/load-test-dynamic-data.yml
shows how you can have your own custom logic to generate random test data everytime. -
Run the load test using bash scripts under
load-test
directory:./run-load-tests-static-data.sh
./run-load-tests-dynamic-data.sh
Make sure the STACK_NAME in the bash script matches with the one deployed using
sam deploy
command earlier. You can also find the stack name fromsamconfig.toml
file.
- Generating an HTML report:
-
First, run a test and create a JSON report with the --output flag in above script.
artillery run load-test-static-data.yml --target $API_URL --output test-run-report.json
-
You can then use the generated JSON report to create an HTML report:
artillery report test-run-report.json
. -
This will create a
test-run-report.json.html
file in the current directory which you can open in a browser.
-
For more information, please refer to the artillery documentation
Run the given command to delete the resources that were created. It might take some time for the CloudFormation stack to get deleted.
sam delete --stack-name <STACK_NAME>