Skip to content

Commit b2dd36f

Browse files
adding backend as a service with lambda + api gateway + dynamodb
1 parent af69738 commit b2dd36f

14 files changed

Lines changed: 579 additions & 9 deletions

File tree

pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@
4949
<slf4j.version>1.7.21</slf4j.version>
5050
<logback.version>1.1.7</logback.version>
5151
<aws-lambda-core.version>1.1.0</aws-lambda-core.version>
52+
<aws-java-sdk-dynamodb.version>1.11.289</aws-java-sdk-dynamodb.version>
5253
<aws-lambda-log4j.version>1.0.0</aws-lambda-log4j.version>
54+
<aws-lambda-java-events.version>2.0.1</aws-lambda-java-events.version>
5355
<jackson.version>2.8.5</jackson.version>
5456
</properties>
5557
<modules>

serverless/pom.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,26 @@
3535
<artifactId>aws-lambda-java-core</artifactId>
3636
<version>${aws-lambda-core.version}</version>
3737
</dependency>
38+
<dependency>
39+
<groupId>com.amazonaws</groupId>
40+
<artifactId>aws-java-sdk-dynamodb</artifactId>
41+
<version>${aws-java-sdk-dynamodb.version}</version>
42+
<exclusions>
43+
<exclusion>
44+
<groupId>com.amazonaws</groupId>
45+
<artifactId>aws-java-sdk-s3</artifactId>
46+
</exclusion>
47+
<exclusion>
48+
<groupId>com.amazonaws</groupId>
49+
<artifactId>aws-java-sdk-kms</artifactId>
50+
</exclusion>
51+
</exclusions>
52+
</dependency>
53+
<dependency>
54+
<groupId>com.amazonaws</groupId>
55+
<artifactId>aws-lambda-java-events</artifactId>
56+
<version>${aws-lambda-java-events.version}</version>
57+
</dependency>
3858
<dependency>
3959
<groupId>com.amazonaws</groupId>
4060
<artifactId>aws-lambda-java-log4j</artifactId>

serverless/serverless.yml

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
# THE SOFTWARE.
2222
#
2323

24-
service: lambda-info-http-endpoint
24+
service: serverless-services
2525

2626
frameworkVersion: ">=1.2.0 <2.0.0"
2727

@@ -41,9 +41,62 @@ package:
4141
artifact: target/serverless.jar
4242

4343
functions:
44-
currentTime:
45-
handler: com.iluwatar.serverless.api.LambdaInfoApiHandler
44+
lambdaInfoApi:
45+
handler: com.iluwatar.serverless.faas.api.LambdaInfoApiHandler
4646
events:
4747
- http:
4848
path: info
4949
method: get
50+
51+
savePerson:
52+
handler: com.iluwatar.serverless.baas.api.SavePersonApiHandler
53+
events:
54+
- http:
55+
path: api/person
56+
method: post
57+
cors: true
58+
integration: lambda-proxy
59+
60+
getPerson:
61+
handler: com.iluwatar.serverless.baas.api.FindPersonApiHandlerr
62+
events:
63+
- http:
64+
path: api/person/{id}
65+
method: get
66+
cors: true
67+
integration: lambda-proxy
68+
69+
resources:
70+
Resources:
71+
DynamoDbTable:
72+
Type: AWS::DynamoDB::Table
73+
Properties:
74+
TableName: persons
75+
AttributeDefinitions:
76+
- AttributeName: id
77+
AttributeType: S
78+
KeySchema:
79+
- AttributeName: id
80+
KeyType: HASH
81+
ProvisionedThroughput:
82+
ReadCapacityUnits: 1
83+
WriteCapacityUnits: 1
84+
DynamoDBIamPolicy:
85+
Type: AWS::IAM::Policy
86+
DependsOn: DynamoDbTable
87+
Properties:
88+
PolicyName: lambda-dynamodb
89+
PolicyDocument:
90+
Version: '2012-10-17'
91+
Statement:
92+
- Effect: Allow
93+
Action:
94+
- dynamodb:GetItem
95+
- dynamodb:PutItem
96+
- dynamodb:UpdateItem
97+
- dynamodb:DeleteItem
98+
- dynamodb:Query
99+
- dynamodb:Scan
100+
Resource: arn:aws:dynamodb:*:*:table/persons
101+
Roles:
102+
- Ref: IamRoleLambdaExecution
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package com.iluwatar.serverless.baas.api;
2+
3+
import com.amazonaws.regions.Regions;
4+
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
5+
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
6+
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
7+
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
8+
import com.fasterxml.jackson.core.JsonProcessingException;
9+
import com.fasterxml.jackson.databind.ObjectMapper;
10+
11+
import java.io.Serializable;
12+
import java.util.HashMap;
13+
import java.util.Map;
14+
15+
/**
16+
* abstract dynamodb handler
17+
* @param <T> - serializable collection
18+
*/
19+
public abstract class AbstractDynamoDbHandler<T extends Serializable> {
20+
private DynamoDBMapper dynamoDbMapper;
21+
22+
private ObjectMapper objectMapper;
23+
24+
public AbstractDynamoDbHandler() {
25+
this.initAmazonDynamoDb();
26+
this.objectMapper = new ObjectMapper();
27+
}
28+
29+
private void initAmazonDynamoDb() {
30+
AmazonDynamoDB amazonDynamoDb = AmazonDynamoDBClientBuilder
31+
.standard()
32+
.withRegion(Regions.US_EAST_1)
33+
.build();
34+
35+
this.dynamoDbMapper = new DynamoDBMapper(amazonDynamoDb);
36+
}
37+
38+
protected DynamoDBMapper getDynamoDbMapper() {
39+
return this.dynamoDbMapper;
40+
}
41+
42+
protected ObjectMapper getObjectMapper() {
43+
return objectMapper;
44+
}
45+
46+
public void setDynamoDbMapper(DynamoDBMapper dynamoDbMapper) {
47+
this.dynamoDbMapper = dynamoDbMapper;
48+
}
49+
50+
protected Map<String, String> headers() {
51+
Map<String, String> headers = new HashMap<>();
52+
headers.put("Content-Type", "application/json");
53+
54+
return headers;
55+
}
56+
57+
/**
58+
* API Gateway response
59+
*
60+
* @param statusCode - status code
61+
* @param body - Object body
62+
* @return - api gateway proxy response
63+
*/
64+
protected APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent(Integer statusCode, T body) {
65+
APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent =
66+
new APIGatewayProxyResponseEvent().withHeaders(headers());
67+
try {
68+
apiGatewayProxyResponseEvent
69+
.withStatusCode(statusCode)
70+
.withBody(getObjectMapper()
71+
.writeValueAsString(body));
72+
73+
} catch (JsonProcessingException jsonProcessingException) {
74+
throw new RuntimeException(jsonProcessingException);
75+
}
76+
77+
return apiGatewayProxyResponseEvent;
78+
}
79+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.iluwatar.serverless.baas.api;
2+
3+
import com.amazonaws.services.lambda.runtime.Context;
4+
import com.amazonaws.services.lambda.runtime.RequestHandler;
5+
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
6+
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
7+
import com.iluwatar.serverless.baas.model.Person;
8+
import org.apache.log4j.Logger;
9+
10+
/**
11+
* find person from persons collection
12+
* Created by dheeraj.mummar on 3/5/18.
13+
*/
14+
public class FindPersonApiHandler extends AbstractDynamoDbHandler
15+
implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
16+
17+
private static final Logger LOG = Logger.getLogger(FindPersonApiHandler.class);
18+
private static final Integer SUCCESS_STATUS_CODE = 200;
19+
20+
@Override
21+
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent,
22+
Context context) {
23+
LOG.info(apiGatewayProxyRequestEvent.getPathParameters());
24+
Person person = this.getDynamoDbMapper().load(Person.class, apiGatewayProxyRequestEvent
25+
.getPathParameters().get("id"));
26+
27+
return apiGatewayProxyResponseEvent(SUCCESS_STATUS_CODE, person);
28+
}
29+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.iluwatar.serverless.baas.api;
2+
3+
import com.amazonaws.services.lambda.runtime.Context;
4+
import com.amazonaws.services.lambda.runtime.RequestHandler;
5+
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
6+
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
7+
import com.iluwatar.serverless.baas.model.Person;
8+
import org.apache.log4j.Logger;
9+
10+
import java.io.IOException;
11+
12+
/**
13+
* save person into persons collection
14+
* Created by dheeraj.mummar on 3/4/18.
15+
*/
16+
public class SavePersonApiHandler extends AbstractDynamoDbHandler
17+
implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
18+
19+
private static final Logger LOG = Logger.getLogger(SavePersonApiHandler.class);
20+
private static final Integer CREATED_STATUS_CODE = 201;
21+
private static final Integer BAD_REQUEST_STATUS_CODE = 400;
22+
23+
@Override
24+
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent
25+
apiGatewayProxyRequestEvent, Context context) {
26+
APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent;
27+
Person person;
28+
try {
29+
person = getObjectMapper().readValue(apiGatewayProxyRequestEvent.getBody(), Person.class);
30+
getDynamoDbMapper().save(person);
31+
apiGatewayProxyResponseEvent = apiGatewayProxyResponseEvent(CREATED_STATUS_CODE, person);
32+
} catch (IOException ioException) {
33+
LOG.error("unable to parse body", ioException);
34+
apiGatewayProxyResponseEvent = apiGatewayProxyResponseEvent(BAD_REQUEST_STATUS_CODE, null);
35+
}
36+
37+
return apiGatewayProxyResponseEvent;
38+
}
39+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package com.iluwatar.serverless.baas.model;
2+
3+
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
4+
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBDocument;
5+
6+
import java.io.Serializable;
7+
8+
/**
9+
* Address Object
10+
* Created by dheeraj.mummarareddy on 3/4/18.
11+
*/
12+
@DynamoDBDocument
13+
public class Address implements Serializable {
14+
15+
private static final long serialVersionUID = 6760844284799736970L;
16+
17+
private String addressLineOne;
18+
private String addressLineTwo;
19+
private String city;
20+
private String state;
21+
private String zipCode;
22+
23+
@DynamoDBAttribute(attributeName = "addressLineOne")
24+
public String getAddressLineOne() {
25+
return addressLineOne;
26+
}
27+
28+
public void setAddressLineOne(String addressLineOne) {
29+
this.addressLineOne = addressLineOne;
30+
}
31+
32+
@DynamoDBAttribute(attributeName = "addressLineTwo")
33+
public String getAddressLineTwo() {
34+
return addressLineTwo;
35+
}
36+
37+
public void setAddressLineTwo(String addressLineTwo) {
38+
this.addressLineTwo = addressLineTwo;
39+
}
40+
41+
@DynamoDBAttribute(attributeName = "city")
42+
public String getCity() {
43+
return city;
44+
}
45+
46+
public void setCity(String city) {
47+
this.city = city;
48+
}
49+
50+
@DynamoDBAttribute(attributeName = "state")
51+
public String getState() {
52+
return state;
53+
}
54+
55+
public void setState(String state) {
56+
this.state = state;
57+
}
58+
59+
@DynamoDBAttribute(attributeName = "zipCode")
60+
public String getZipCode() {
61+
return zipCode;
62+
}
63+
64+
public void setZipCode(String zipCode) {
65+
this.zipCode = zipCode;
66+
}
67+
68+
@Override
69+
public boolean equals(Object o) {
70+
if (this == o) {
71+
return true;
72+
}
73+
74+
if (o == null || getClass() != o.getClass()) {
75+
return false;
76+
}
77+
78+
Address address = (Address) o;
79+
80+
if (addressLineOne != null ? !addressLineOne.equals(address.addressLineOne) :
81+
address.addressLineOne != null) {
82+
return false;
83+
}
84+
85+
if (addressLineTwo != null ? !addressLineTwo.equals(address.addressLineTwo) :
86+
address.addressLineTwo != null) {
87+
return false;
88+
}
89+
90+
if (city != null ? !city.equals(address.city) : address.city != null) {
91+
return false;
92+
}
93+
if (state != null ? !state.equals(address.state) : address.state != null) {
94+
return false;
95+
}
96+
return zipCode != null ? zipCode.equals(address.zipCode) : address.zipCode == null;
97+
}
98+
99+
@Override
100+
public int hashCode() {
101+
int result = addressLineOne != null ? addressLineOne.hashCode() : 0;
102+
result = 31 * result + (addressLineTwo != null ? addressLineTwo.hashCode() : 0);
103+
result = 31 * result + (city != null ? city.hashCode() : 0);
104+
result = 31 * result + (state != null ? state.hashCode() : 0);
105+
result = 31 * result + (zipCode != null ? zipCode.hashCode() : 0);
106+
return result;
107+
}
108+
109+
@Override
110+
public String toString() {
111+
return "Address{"
112+
+ "addressLineOne='" + addressLineOne + '\''
113+
+ ", addressLineTwo='" + addressLineTwo + '\''
114+
+ ", city='" + city + '\''
115+
+ ", state='" + state + '\''
116+
+ ", zipCode='" + zipCode + '\''
117+
+ '}';
118+
}
119+
}

0 commit comments

Comments
 (0)