Merge pull request #714 from dheeraj-mummareddy/master

#473 serveless implementation using aws compute engine and serverless fram…
This commit is contained in:
Ilkka Seppälä 2018-04-08 20:01:42 +03:00 committed by GitHub
commit 379a825182
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1558 additions and 0 deletions

View File

@ -48,6 +48,11 @@
<mongo-java-driver.version>3.3.0</mongo-java-driver.version> <mongo-java-driver.version>3.3.0</mongo-java-driver.version>
<slf4j.version>1.7.21</slf4j.version> <slf4j.version>1.7.21</slf4j.version>
<logback.version>1.1.7</logback.version> <logback.version>1.1.7</logback.version>
<aws-lambda-core.version>1.1.0</aws-lambda-core.version>
<aws-java-sdk-dynamodb.version>1.11.289</aws-java-sdk-dynamodb.version>
<aws-lambda-log4j.version>1.0.0</aws-lambda-log4j.version>
<aws-lambda-java-events.version>2.0.1</aws-lambda-java-events.version>
<jackson.version>2.8.5</jackson.version>
</properties> </properties>
<modules> <modules>
<module>abstract-factory</module> <module>abstract-factory</module>
@ -154,6 +159,7 @@
<module>eip-aggregator</module> <module>eip-aggregator</module>
<module>retry</module> <module>retry</module>
<module>trampoline</module> <module>trampoline</module>
<module>serverless</module>
</modules> </modules>
<repositories> <repositories>

199
serverless/README.md Normal file
View File

@ -0,0 +1,199 @@
---
layout: pattern
title: serverless
folder: serverless
permalink: /patterns/serverless/
categories: Architectural
tags:
- Java
- Difficulty-Intermediate
---
## Serverless
Serverless eliminates the need to plan for infrastructure and let's you focus on your
application.
Following are optimization katas you should be aware of while building a serverless
applications
* The Lean function
* Concise logic - Use functions to transform, not transport (utilize some of the
integration available from the provider to transport), and make sure you read only
what you need
* Efficient/single purpose code - avoid conditional/routing logic and break down
into individual functions, avoid "fat"/monolithic functions and control the
dependencies in the function deployment package to reduce the load time for your
function
* ephemeral environment - Utilize container start for expensive initializations
* Eventful Invocations
* Succinct payloads - Scrutinize the event as much as possible, and watch for
payload constraints (async - 128K)
* resilient routing - Understand retry policies and leverage dead letter queues
(SQS or SNS for replays) and remember retries count as invocations
* concurrent execution - lambda thinks of it's scale in terms of concurrency and
its not request based/duration based. Lambda will spin up the number of instances
based on the request.
* Coordinated calls
* Decoupled via APIs - best practice to setup your application is to have API's as
contracts that ensures separation of concerns
* scale-matched downstream - make sure when Lambda is calling downstream
components, you are matching scale configuration to it (by specifying max
concurrency based on downstream services)
* secured - Always ask a question, do I need a VPC?
* Serviceful operations
* Automated - use automated tools to manage and maintain the stack
* monitored applications - use monitoring services to get holistic view of your
serverless applications
## Intent
Whether to reduce your infrastructure costs, shrink the time you spend on ops tasks,
simplify your deployment processes, reach infinite scalability, serverless cuts time
to market in half.
## Explanation
Serverless computing is a cloud computing execution model in which the cloud provider
dynamically manages the allocation of machine resources. Pricing is based on the
actual amount of resources consumed by an application, rather than on pre-purchased
units of capacity.
## Serverless framework
[Serverless](https://serverless.com/) is a toolkit for deploying and operating serverless architectures.
## (Function as a Service or "FaaS")
The term Serverless is confusing since with such applications there are both server
hardware and server processes running somewhere, but the difference to normal
approaches is that the organization building and supporting a Serverless application
is not looking after the hardware or the processes - they are outsourcing this to a vendor.
Some of the Serverless Cloud Providers are
![https://serverless.com/framework/docs/providers/aws/](./etc/aws-black.png "aws")
![https://serverless.com/framework/docs/providers/azure/](./etc/azure-black.png "azure")
![https://serverless.com/framework/docs/providers/openwhisk/](./etc/openwhisk-black.png "openwhisk")
![https://serverless.com/framework/docs/providers/google/](./etc/gcf-black.png "google")
![https://serverless.com/framework/docs/providers/kubeless/](./etc/kubeless-logos-black.png "kubeless")
![https://serverless.com/framework/docs/providers/spotinst/](./etc/spotinst-logos-black-small.png "spotinst")
![https://serverless.com/framework/docs/providers/webtasks/](./etc/webtask-small-grayscale.png "webtask")
...
Anything that triggers an Lambda Function to execute is regarded by the Framework as
an Event. Most of the Serverless Cloud Providers support following Events
- Http
- PubSub Events
- scheduled
AWS supports processing event generated from AWS Services (S3/Cloudwatch/etc) and
using aws as a compute engine is our first choice.
## (Backend as a Service or "BaaS")
This example creates a backend for persons collection which uses DynamoDB NoSQL
database service also provided by Amazon.
## AWS lambda function implementation
[AWS Lambda SDK](https://aws.amazon.com/sdk-for-java/) provides pre-defined interface
`com.amazonaws.services.lambda.runtime
.RequestHandler` to implement our lambda function.
```java
public class LambdaInfoApiHandler implements RequestHandler<Map<String, Object>, ApiGatewayResponse> {
private static final Logger LOG = Logger.getLogger(LambdaInfoApiHandler.class);
private static final Integer SUCCESS_STATUS_CODE = 200;
@Override
public ApiGatewayResponse handleRequest(Map<String, Object> input, Context context) {
}
}
```
handleRequest method is where the function code is implemented. Context provides
useful information about Lambda execution environment. AWS Lambda function needs a
deployment package. This package is either a .zip or .jar file that contains all the
dependencies of the function.
`serverless.yml` contains configuration to manage deployments for your functions.
## Run example in local
# Pre-requisites
* Node.js v6.5.0 or later.
* Serverless CLI v1.9.0 or later. You can run npm install -g serverless to install it.
* An AWS account. If you don't already have one, you can sign up for a free trial that includes 1 million free Lambda requests per month.
* [Set-up](https://serverless.com/framework/docs/providers/aws/guide/credentials/) your Provider Credentials. Watch the video on setting up credentials
# build and deploy
* `cd serverless`
* `mvn clean package`
* `serverless deploy --stage=dev --verbose`
Based on the configuration in `serverless.yml` serverless framework creates following
resources
* CloudFormation stack for S3 (ServerlessDeploymentBucket)
* IAM Role (IamRoleLambdaExecution)
* CloudWatch (log groups)
* API Gateway (ApiGatewayRestApi)
* Lambda function
* DynamoDB collection
The command will print out Stack Outputs which looks something like this
```yaml
endpoints:
GET - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/info
POST - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person
GET - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person/{id}
```
```yaml
CurrentTimeLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-1:xxxxxxxxxxx:function:lambda-info-http-endpoint-dev-currentTime:4
ServiceEndpoint: https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev
ServerlessDeploymentBucketName: lambda-info-http-endpoin-serverlessdeploymentbuck-2u8uz2i7cap2
```
access the endpoint to invoke the function.
Use the following cURL commands to test the endpoints
```cURL
curl -X GET \
https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/info \
-H 'cache-control: no-cache'
```
```cURL
curl -X POST \
https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d '{
"firstName": "Thor",
"lastName": "Odinson",
"address": {
"addressLineOne": "1 Odin ln",
"addressLineTwo": "100",
"city": "Asgard",
"state": "country of the Gods",
"zipCode": "00001"
}
}'
```
```cURL
curl -X GET \
https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person/{id} \
-H 'cache-control: no-cache'
```
## Credits
* [serverless docs](https://serverless.com/framework/docs/)
* [Serverless Architectures](https://martinfowler.com/articles/serverless.html)
* [Serverless Black Belt](https://youtu.be/oQFORsso2go)

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

133
serverless/pom.xml Normal file
View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
The MIT License
Copyright (c) 2014-2017 Ilkka Seppälä
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>serverless</artifactId>
<parent>
<groupId>com.iluwatar</groupId>
<artifactId>java-design-patterns</artifactId>
<version>1.20.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>${aws-lambda-core.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>${aws-java-sdk-dynamodb.version}</version>
<exclusions>
<exclusion>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
</exclusion>
<exclusion>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-kms</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-events</artifactId>
<version>${aws-lambda-java-events.version}</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-log4j</artifactId>
<version>${aws-lambda-log4j.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!--
Using the Apache Maven Shade plugin to package the jar
"This plugin provides the capability to package the artifact
in an uber-jar, including its dependencies and to shade - i.e. rename -
the packages of some of the dependencies."
Link: https://maven.apache.org/plugins/maven-shade-plugin/
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>${project.artifactId}</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

102
serverless/serverless.yml Normal file
View File

@ -0,0 +1,102 @@
#
# The MIT License
# Copyright (c) 2014 Ilkka Seppälä
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
service: serverless-services
frameworkVersion: ">=1.2.0 <2.0.0"
provider:
name: aws
runtime: java8
usagePlan:
quota:
limit: 500
offset: 2
period: MONTH
throttle:
burstLimit: 20
rateLimit: 10
package:
artifact: target/serverless.jar
functions:
lambdaInfoApi:
handler: com.iluwatar.serverless.faas.api.LambdaInfoApiHandler
events:
- http:
path: info
method: get
savePerson:
handler: com.iluwatar.serverless.baas.api.SavePersonApiHandler
events:
- http:
path: api/person
method: post
cors: true
integration: lambda-proxy
getPerson:
handler: com.iluwatar.serverless.baas.api.FindPersonApiHandler
events:
- http:
path: api/person/{id}
method: get
cors: true
integration: lambda-proxy
resources:
Resources:
DynamoDbTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: persons
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
DynamoDBIamPolicy:
Type: AWS::IAM::Policy
DependsOn: DynamoDbTable
Properties:
PolicyName: lambda-dynamodb
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
- dynamodb:Query
- dynamodb:Scan
Resource: arn:aws:dynamodb:*:*:table/persons
Roles:
- Ref: IamRoleLambdaExecution

View File

@ -0,0 +1,101 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.serverless.baas.api;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* abstract dynamodb handler
* @param <T> - serializable collection
*/
public abstract class AbstractDynamoDbHandler<T extends Serializable> {
private DynamoDBMapper dynamoDbMapper;
private ObjectMapper objectMapper;
public AbstractDynamoDbHandler() {
this.initAmazonDynamoDb();
this.objectMapper = new ObjectMapper();
}
private void initAmazonDynamoDb() {
AmazonDynamoDB amazonDynamoDb = AmazonDynamoDBClientBuilder
.standard()
.withRegion(Regions.US_EAST_1)
.build();
this.dynamoDbMapper = new DynamoDBMapper(amazonDynamoDb);
}
protected DynamoDBMapper getDynamoDbMapper() {
return this.dynamoDbMapper;
}
protected ObjectMapper getObjectMapper() {
return objectMapper;
}
public void setDynamoDbMapper(DynamoDBMapper dynamoDbMapper) {
this.dynamoDbMapper = dynamoDbMapper;
}
protected Map<String, String> headers() {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
return headers;
}
/**
* API Gateway response
*
* @param statusCode - status code
* @param body - Object body
* @return - api gateway proxy response
*/
protected APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent(Integer statusCode, T body) {
APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent =
new APIGatewayProxyResponseEvent().withHeaders(headers());
try {
apiGatewayProxyResponseEvent
.withStatusCode(statusCode)
.withBody(getObjectMapper()
.writeValueAsString(body));
} catch (JsonProcessingException jsonProcessingException) {
throw new RuntimeException(jsonProcessingException);
}
return apiGatewayProxyResponseEvent;
}
}

View File

@ -0,0 +1,51 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.serverless.baas.api;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.iluwatar.serverless.baas.model.Person;
import org.apache.log4j.Logger;
/**
* find person from persons collection
* Created by dheeraj.mummar on 3/5/18.
*/
public class FindPersonApiHandler extends AbstractDynamoDbHandler
implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
private static final Logger LOG = Logger.getLogger(FindPersonApiHandler.class);
private static final Integer SUCCESS_STATUS_CODE = 200;
@Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent,
Context context) {
LOG.info(apiGatewayProxyRequestEvent.getPathParameters());
Person person = this.getDynamoDbMapper().load(Person.class, apiGatewayProxyRequestEvent
.getPathParameters().get("id"));
return apiGatewayProxyResponseEvent(SUCCESS_STATUS_CODE, person);
}
}

View File

@ -0,0 +1,61 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.serverless.baas.api;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.iluwatar.serverless.baas.model.Person;
import org.apache.log4j.Logger;
import java.io.IOException;
/**
* save person into persons collection
* Created by dheeraj.mummar on 3/4/18.
*/
public class SavePersonApiHandler extends AbstractDynamoDbHandler
implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
private static final Logger LOG = Logger.getLogger(SavePersonApiHandler.class);
private static final Integer CREATED_STATUS_CODE = 201;
private static final Integer BAD_REQUEST_STATUS_CODE = 400;
@Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent
apiGatewayProxyRequestEvent, Context context) {
APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent;
Person person;
try {
person = getObjectMapper().readValue(apiGatewayProxyRequestEvent.getBody(), Person.class);
getDynamoDbMapper().save(person);
apiGatewayProxyResponseEvent = apiGatewayProxyResponseEvent(CREATED_STATUS_CODE, person);
} catch (IOException ioException) {
LOG.error("unable to parse body", ioException);
apiGatewayProxyResponseEvent = apiGatewayProxyResponseEvent(BAD_REQUEST_STATUS_CODE, null);
}
return apiGatewayProxyResponseEvent;
}
}

View File

@ -0,0 +1,141 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.serverless.baas.model;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBDocument;
import java.io.Serializable;
/**
* Address class
* Created by dheeraj.mummarareddy on 3/4/18.
*/
@DynamoDBDocument
public class Address implements Serializable {
private static final long serialVersionUID = 6760844284799736970L;
private String addressLineOne;
private String addressLineTwo;
private String city;
private String state;
private String zipCode;
@DynamoDBAttribute(attributeName = "addressLineOne")
public String getAddressLineOne() {
return addressLineOne;
}
public void setAddressLineOne(String addressLineOne) {
this.addressLineOne = addressLineOne;
}
@DynamoDBAttribute(attributeName = "addressLineTwo")
public String getAddressLineTwo() {
return addressLineTwo;
}
public void setAddressLineTwo(String addressLineTwo) {
this.addressLineTwo = addressLineTwo;
}
@DynamoDBAttribute(attributeName = "city")
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@DynamoDBAttribute(attributeName = "state")
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@DynamoDBAttribute(attributeName = "zipCode")
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Address address = (Address) o;
if (addressLineOne != null ? !addressLineOne.equals(address.addressLineOne) :
address.addressLineOne != null) {
return false;
}
if (addressLineTwo != null ? !addressLineTwo.equals(address.addressLineTwo) :
address.addressLineTwo != null) {
return false;
}
if (city != null ? !city.equals(address.city) : address.city != null) {
return false;
}
if (state != null ? !state.equals(address.state) : address.state != null) {
return false;
}
return zipCode != null ? zipCode.equals(address.zipCode) : address.zipCode == null;
}
@Override
public int hashCode() {
int result = addressLineOne != null ? addressLineOne.hashCode() : 0;
result = 31 * result + (addressLineTwo != null ? addressLineTwo.hashCode() : 0);
result = 31 * result + (city != null ? city.hashCode() : 0);
result = 31 * result + (state != null ? state.hashCode() : 0);
result = 31 * result + (zipCode != null ? zipCode.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Address{"
+ "addressLineOne='" + addressLineOne + '\''
+ ", addressLineTwo='" + addressLineTwo + '\''
+ ", city='" + city + '\''
+ ", state='" + state + '\''
+ ", zipCode='" + zipCode + '\''
+ '}';
}
}

View File

@ -0,0 +1,124 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.serverless.baas.model;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
/**
* Person class
* Created by dheeraj.mummarareddy on 3/4/18.
*/
@DynamoDBTable(tableName = "persons")
public class Person implements Serializable {
private static final long serialVersionUID = -3413087924608627075L;
private String id;
private String firstName;
private String lastName;
private Address address;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@DynamoDBHashKey(attributeName = "id")
@DynamoDBAutoGeneratedKey
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@DynamoDBAttribute(attributeName = "firstName")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@DynamoDBAttribute(attributeName = "lastName")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@DynamoDBAttribute(attributeName = "address")
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Person person = (Person) o;
if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) {
return false;
}
if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) {
return false;
}
return address != null ? address.equals(person.address) : person.address == null;
}
@Override
public int hashCode() {
int result = firstName != null ? firstName.hashCode() : 0;
result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
result = 31 * result + (address != null ? address.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Person{"
+ "id='" + id + '\''
+ ", firstName='" + firstName + '\''
+ ", lastName='" + lastName + '\''
+ ", address=" + address
+ '}';
}
}

View File

@ -0,0 +1,166 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.serverless.faas;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.Serializable;
import java.util.Map;
/**
* Api gateway response
*
* @param <T> serializable object
*/
public class ApiGatewayResponse<T extends Serializable> implements Serializable {
private static final long serialVersionUID = 1181159426782844892L;
private final Integer statusCode;
private final String body;
private final Map<String, String> headers;
private final Boolean isBase64Encoded;
/**
* api gateway response
*
* @param statusCode - http status code
* @param body - response body
* @param headers - response headers
* @param isBase64Encoded - base64Encoded flag
*/
public ApiGatewayResponse(Integer statusCode, String body, Map<String, String> headers,
Boolean isBase64Encoded) {
this.statusCode = statusCode;
this.body = body;
this.headers = headers;
this.isBase64Encoded = isBase64Encoded;
}
/**
* http status code
*
* @return statusCode - http status code
*/
public Integer getStatusCode() {
return statusCode;
}
/**
* response body
*
* @return string body
*/
public String getBody() {
return body;
}
/**
* response headers
*
* @return response headers
*/
public Map<String, String> getHeaders() {
return headers;
}
/**
* base64Encoded flag, API Gateway expects the property to be called "isBase64Encoded"
*
* @return base64Encoded flag
*/
public Boolean isBase64Encoded() {
return isBase64Encoded;
}
/**
* ApiGatewayResponse Builder class
* @param <T> Serializable object
*/
public static class ApiGatewayResponseBuilder<T extends Serializable> {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private Integer statusCode;
private T body;
private Map<String, String> headers;
private Boolean isBase64Encoded;
/**
* http status code
* @param statusCode - http status code
* @return ApiGatewayResponseBuilder
*/
public ApiGatewayResponseBuilder statusCode(Integer statusCode) {
this.statusCode = statusCode;
return this;
}
/**
* Serializable body
* @param body - Serializable object
* @return ApiGatewayResponseBuilder
*/
public ApiGatewayResponseBuilder body(T body) {
this.body = body;
return this;
}
/**
* response headers
* @param headers - response headers
* @return ApiGatewayResponseBuilder
*/
public ApiGatewayResponseBuilder headers(Map<String, String> headers) {
this.headers = headers;
return this;
}
/**
* base64Encoded glag
* @param isBase64Encoded - base64Encoded flag
* @return ApiGatewayResponseBuilder
*/
public ApiGatewayResponseBuilder base64Encoded(Boolean isBase64Encoded) {
this.isBase64Encoded = isBase64Encoded;
return this;
}
/**
* build ApiGatewayResponse
*
* @return ApiGatewayResponse
*/
public ApiGatewayResponse build() {
String strBody = null;
if (this.body != null) {
try {
strBody = OBJECT_MAPPER.writeValueAsString(body);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
return new ApiGatewayResponse(this.statusCode, strBody, this.headers, this.isBase64Encoded);
}
}
}

View File

@ -0,0 +1,140 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.serverless.faas;
import java.io.Serializable;
/**
* Lambda context information
*/
public class LambdaInfo implements Serializable {
private static final long serialVersionUID = 3936130599040848923L;
private String awsRequestId;
private String logGroupName;
private String logStreamName;
private String functionName;
private String functionVersion;
private Integer memoryLimitInMb;
public String getAwsRequestId() {
return awsRequestId;
}
public void setAwsRequestId(String awsRequestId) {
this.awsRequestId = awsRequestId;
}
public String getLogGroupName() {
return logGroupName;
}
public void setLogGroupName(String logGroupName) {
this.logGroupName = logGroupName;
}
public String getLogStreamName() {
return logStreamName;
}
public void setLogStreamName(String logStreamName) {
this.logStreamName = logStreamName;
}
public String getFunctionName() {
return functionName;
}
public void setFunctionName(String functionName) {
this.functionName = functionName;
}
public String getFunctionVersion() {
return functionVersion;
}
public void setFunctionVersion(String functionVersion) {
this.functionVersion = functionVersion;
}
public Integer getMemoryLimitInMb() {
return memoryLimitInMb;
}
public void setMemoryLimitInMb(Integer memoryLimitInMb) {
this.memoryLimitInMb = memoryLimitInMb;
}
@Override
public String toString() {
return "LambdaInfo{"
+ "awsRequestId='" + awsRequestId + '\''
+ ", logGroupName='" + logGroupName + '\''
+ ", logStreamName='" + logStreamName + '\''
+ ", functionName='" + functionName + '\''
+ ", functionVersion='" + functionVersion + '\''
+ ", memoryLimitInMb=" + memoryLimitInMb
+ '}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
LambdaInfo that = (LambdaInfo) o;
if (awsRequestId != null ? !awsRequestId.equals(that.awsRequestId) : that.awsRequestId != null) {
return false;
}
if (logGroupName != null ? !logGroupName.equals(that.logGroupName) : that.logGroupName != null) {
return false;
}
if (logStreamName != null ? !logStreamName.equals(that.logStreamName) : that.logStreamName != null) {
return false;
}
if (functionName != null ? !functionName.equals(that.functionName) : that.functionName != null) {
return false;
}
if (functionVersion != null ? !functionVersion.equals(that.functionVersion) : that.functionVersion != null) {
return false;
}
return memoryLimitInMb != null ? memoryLimitInMb.equals(that.memoryLimitInMb) : that.memoryLimitInMb == null;
}
@Override
public int hashCode() {
int result = awsRequestId != null ? awsRequestId.hashCode() : 0;
result = 31 * result + (logGroupName != null ? logGroupName.hashCode() : 0);
result = 31 * result + (logStreamName != null ? logStreamName.hashCode() : 0);
result = 31 * result + (functionName != null ? functionName.hashCode() : 0);
result = 31 * result + (functionVersion != null ? functionVersion.hashCode() : 0);
result = 31 * result + (memoryLimitInMb != null ? memoryLimitInMb.hashCode() : 0);
return result;
}
}

View File

@ -0,0 +1,83 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.serverless.faas.api;
import com.iluwatar.serverless.faas.ApiGatewayResponse;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.iluwatar.serverless.faas.LambdaInfo;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import java.util.HashMap;
import java.util.Map;
/**
* LambdaInfoApiHandler - simple api to get lambda context
* Created by dheeraj.mummar on 2/5/18.
*/
public class LambdaInfoApiHandler implements RequestHandler<Map<String, Object>, ApiGatewayResponse> {
private static final Logger LOG = Logger.getLogger(LambdaInfoApiHandler.class);
private static final Integer SUCCESS_STATUS_CODE = 200;
@Override
public ApiGatewayResponse handleRequest(Map<String, Object> input, Context context) {
BasicConfigurator.configure();
LOG.info("received: " + input);
return new ApiGatewayResponse
.ApiGatewayResponseBuilder<LambdaInfo>()
.headers(headers())
.statusCode(SUCCESS_STATUS_CODE)
.body(lambdaInfo(context))
.build();
}
/**
* lambdaInfo
* @param context - Lambda context
* @return LambdaInfo
*/
private LambdaInfo lambdaInfo(Context context) {
LambdaInfo lambdaInfo = new LambdaInfo();
lambdaInfo.setAwsRequestId(context.getAwsRequestId());
lambdaInfo.setFunctionName(context.getFunctionName());
lambdaInfo.setFunctionVersion(context.getFunctionVersion());
lambdaInfo.setLogGroupName(context.getLogGroupName());
lambdaInfo.setLogStreamName(context.getLogStreamName());
lambdaInfo.setMemoryLimitInMb(context.getMemoryLimitInMB());
return lambdaInfo;
}
private Map<String, String> headers() {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
return headers;
}
}

View File

@ -0,0 +1,29 @@
#
# The MIT License
# Copyright (c) 2014 Ilkka Seppälä
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
log = .
log4j.rootLogger = DEBUG, LAMBDA
log4j.appender.LAMBDA=com.amazonaws.services.lambda.runtime.log4j.LambdaAppender
log4j.appender.LAMBDA.layout=org.apache.log4j.PatternLayout
log4j.appender.LAMBDA.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} <%X{AWSRequestId}> %-5p %c:%L - %m%n

View File

@ -0,0 +1,72 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.serverless.baas.api;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.iluwatar.serverless.baas.api.FindPersonApiHandler;
import com.iluwatar.serverless.baas.api.SavePersonApiHandler;
import com.iluwatar.serverless.baas.model.Person;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.Collections;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Unit tests for FindPersonApiHandler
* Created by dheeraj.mummar on 3/5/18.
*/
@RunWith(MockitoJUnitRunner.class)
public class FindPersonApiHandlerTest {
private FindPersonApiHandler findPersonApiHandler;
@Mock
private DynamoDBMapper dynamoDbMapper;
@Before
public void setUp() {
this.findPersonApiHandler = new FindPersonApiHandler();
this.findPersonApiHandler.setDynamoDbMapper(dynamoDbMapper);
}
@Test
public void handleRequest() {
findPersonApiHandler.handleRequest(apiGatewayProxyRequestEvent(), mock(Context.class));
verify(dynamoDbMapper, times(1)).load(Person.class, "37e7a1fe-3544-473d-b764-18128f02d72d");
}
private APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent() {
return new APIGatewayProxyRequestEvent()
.withPathParamters(Collections
.singletonMap("id", "37e7a1fe-3544-473d-b764-18128f02d72d"));
}
}

View File

@ -0,0 +1,101 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.serverless.baas.api;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iluwatar.serverless.baas.api.SavePersonApiHandler;
import com.iluwatar.serverless.baas.model.Address;
import com.iluwatar.serverless.baas.model.Person;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.*;
/**
* Unit tests for SavePersonApiHandler
* Created by dheeraj.mummar on 3/4/18.
*/
@RunWith(MockitoJUnitRunner.class)
public class SavePersonApiHandlerTest {
private SavePersonApiHandler savePersonApiHandler;
@Mock
private DynamoDBMapper dynamoDbMapper;
private ObjectMapper objectMapper = new ObjectMapper();
@Before
public void setUp() {
this.savePersonApiHandler = new SavePersonApiHandler();
this.savePersonApiHandler.setDynamoDbMapper(dynamoDbMapper);
}
@Test
public void handleRequestSavePersonSuccessful() throws JsonProcessingException {
Person person = newPerson();
APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent =
this.savePersonApiHandler
.handleRequest(apiGatewayProxyRequestEvent(objectMapper.writeValueAsString(person)), mock(Context.class));
verify(dynamoDbMapper, times(1)).save(person);
Assert.assertNotNull(apiGatewayProxyResponseEvent);
Assert.assertEquals(new Integer(201), apiGatewayProxyResponseEvent.getStatusCode());
}
@Test
public void handleRequestSavePersonException() {
APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent =
this.savePersonApiHandler
.handleRequest(apiGatewayProxyRequestEvent("invalid sample request"), mock(Context.class));
Assert.assertNotNull(apiGatewayProxyResponseEvent);
Assert.assertEquals(new Integer(400), apiGatewayProxyResponseEvent.getStatusCode());
}
private APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent(String body) {
APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent = new APIGatewayProxyRequestEvent();
return apiGatewayProxyRequestEvent.withBody(body);
}
private Person newPerson() {
Person person = new Person();
person.setFirstName("Thor");
person.setLastName("Odinson");
Address address = new Address();
address.setAddressLineOne("1 Odin ln");
address.setCity("Asgard");
address.setState("country of the Gods");
address.setZipCode("00001");
person.setAddress(address);
return person;
}
}

View File

@ -0,0 +1,49 @@
/**
* The MIT License
* Copyright (c) 2014 Ilkka Seppälä
* <p>
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* <p>
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* <p>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.iluwatar.serverless.faas.api;
import com.amazonaws.services.lambda.runtime.Context;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsNull.notNullValue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Unit tests for LambdaInfoApiHandler
*/
@RunWith(MockitoJUnitRunner.class)
public class LambdaInfoApiHandlerTest {
@Test
public void handleRequestWithMockContext() {
LambdaInfoApiHandler lambdaInfoApiHandler = new LambdaInfoApiHandler();
Context context = mock(Context.class);
when(context.getAwsRequestId()).thenReturn("mock aws request id");
assertThat(lambdaInfoApiHandler.handleRequest(null, context), notNullValue());
}
}