Skip to content

Commit 4597669

Browse files
committed
Merge branch 'wip-chapter-10-aws-lambda'
2 parents c7174c7 + b7ce7f5 commit 4597669

20 files changed

+903
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
3+
dependencies {
4+
5+
compile "com.amazonaws:aws-lambda-java-core:1.1.0"
6+
compile "com.amazonaws:aws-lambda-java-events:2.0.1"
7+
8+
compile ("io.eventuate.tram.core:eventuate-tram-producer-jdbc:$eventuateTramVersion") {
9+
exclude module: "org.springframework"
10+
}
11+
compile "io.eventuate.tram.core:eventuate-tram-events:$eventuateTramVersion"
12+
compile project(":ftgo-restaurant-service-api")
13+
compile project(":ftgo-common-jpa")
14+
15+
compile "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
16+
17+
compile 'javax.el:javax.el-api:2.2.5'
18+
19+
testCompile "io.eventuate.util:eventuate-util-test:$eventuateUtilVersion"
20+
testCompile "io.eventuate.tram.core:eventuate-tram-test-util:$eventuateTramVersion"
21+
22+
testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
23+
testCompile 'com.jayway.restassured:rest-assured:2.3.0'
24+
testCompile "com.jayway.jsonpath:json-path:2.3.0"
25+
26+
}
27+
28+
task buildZip(type: Zip) {
29+
from compileJava
30+
from processResources
31+
into('lib') {
32+
from configurations.runtime
33+
}
34+
}
35+
36+
build.dependsOn buildZip
37+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
service: ftgo-application-lambda
2+
3+
provider:
4+
name: aws
5+
runtime: java8
6+
timeout: 35
7+
region: ${env:AWS_REGION}
8+
stage: dev
9+
environment:
10+
SPRING_DATASOURCE_DRIVER_CLASS_NAME: com.mysql.jdbc.Driver
11+
SPRING_DATASOURCE_URL: ${env:AWS_RDS_JDBC_URL}
12+
SPRING_DATASOURCE_USERNAME: ${env:AWS_RDS_JDBC_USER_ID}
13+
SPRING_DATASOURCE_PASSWORD: ${env:AWS_RDS_JDBC_USER_PASSWORD}
14+
vpc:
15+
securityGroupIds:
16+
- ${AWS_RDS_SECURITY_GROUP_ID}
17+
subnetIds:
18+
- ${AWS_RDS_SECURITY_VPC_ID}
19+
20+
package:
21+
artifact: build/distributions/ftgo-restaurant-service-aws-lambda.zip
22+
23+
24+
functions:
25+
create-restaurant:
26+
handler: net.chrisrichardson.ftgo.restaurantservice.lambda.CreateRestaurantRequestHandler
27+
events:
28+
- http:
29+
path: restaurants
30+
method: post
31+
find-restaurant:
32+
handler: net.chrisrichardson.ftgo.restaurantservice.lambda.FindRestaurantRequestHandler
33+
events:
34+
- http:
35+
path: restaurants/{restaurantId}
36+
method: get
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package net.chrisrichardson.ftgo.restaurantservice.aws;
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 org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
10+
import static net.chrisrichardson.ftgo.restaurantservice.aws.ApiGatewayResponse.buildErrorResponse;
11+
12+
13+
public abstract class AbstractHttpHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
14+
15+
private Logger log = LoggerFactory.getLogger(this.getClass());
16+
17+
@Override
18+
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
19+
log.debug("Got request: {}", input);
20+
try {
21+
beforeHandling(input, context);
22+
return handleHttpRequest(input, context);
23+
} catch (Exception e) {
24+
log.error("Error handling request id: {}", context.getAwsRequestId(), e);
25+
return buildErrorResponse(new AwsLambdaError(
26+
"Internal Server Error",
27+
"500",
28+
context.getAwsRequestId(),
29+
"Error handling request: " + context.getAwsRequestId() + " " + input.toString()));
30+
}
31+
}
32+
33+
protected void beforeHandling(APIGatewayProxyRequestEvent request, Context context) {
34+
// do nothing
35+
}
36+
37+
protected abstract APIGatewayProxyResponseEvent handleHttpRequest(APIGatewayProxyRequestEvent request, Context context);
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package net.chrisrichardson.ftgo.restaurantservice.aws;
2+
3+
import org.apache.commons.lang.builder.ToStringBuilder;
4+
5+
import java.util.Map;
6+
import java.util.Optional;
7+
8+
public class ApiGatewayRequest {
9+
10+
private String resource;
11+
private String path;
12+
private String httpMethod;
13+
private Map<String, String> headers;
14+
private Map<String, String> queryStringParameters;
15+
private Map<String, String> pathParameters;
16+
private Map<String, String> stageVariables;
17+
private RequestContext requestContext;
18+
private String body;
19+
private boolean isBase64Encoded;
20+
21+
public String getResource() {
22+
return resource;
23+
}
24+
25+
public void setResource(String resource) {
26+
this.resource = resource;
27+
}
28+
29+
public String getPath() {
30+
return path;
31+
}
32+
33+
public void setPath(String path) {
34+
this.path = path;
35+
}
36+
37+
public String getHttpMethod() {
38+
return httpMethod;
39+
}
40+
41+
public void setHttpMethod(String httpMethod) {
42+
this.httpMethod = httpMethod;
43+
}
44+
45+
public Map<String, String> getHeaders() {
46+
return headers;
47+
}
48+
49+
public void setHeaders(Map<String, String> headers) {
50+
this.headers = headers;
51+
}
52+
53+
public Map<String, String> getQueryStringParameters() {
54+
return queryStringParameters;
55+
}
56+
57+
public void setQueryStringParameters(Map<String, String> queryStringParameters) {
58+
this.queryStringParameters = queryStringParameters;
59+
}
60+
61+
public Map<String, String> getPathParameters() {
62+
return pathParameters;
63+
}
64+
65+
public void setPathParameters(Map<String, String> pathParameters) {
66+
this.pathParameters = pathParameters;
67+
}
68+
69+
public Map<String, String> getStageVariables() {
70+
return stageVariables;
71+
}
72+
73+
public void setStageVariables(Map<String, String> stageVariables) {
74+
this.stageVariables = stageVariables;
75+
}
76+
77+
public RequestContext getRequestContext() {
78+
return requestContext;
79+
}
80+
81+
public void setRequestContext(RequestContext requestContext) {
82+
this.requestContext = requestContext;
83+
}
84+
85+
public String getBody() {
86+
return body;
87+
}
88+
89+
public void setBody(String body) {
90+
this.body = body;
91+
}
92+
93+
public boolean isBase64Encoded() {
94+
return isBase64Encoded;
95+
}
96+
97+
public void setBase64Encoded(boolean base64Encoded) {
98+
isBase64Encoded = base64Encoded;
99+
}
100+
101+
@Override
102+
public String toString() {
103+
return ToStringBuilder.reflectionToString(this);
104+
}
105+
106+
public String getPathParam(String paramName) {
107+
return Optional.ofNullable(this.getPathParameters())
108+
.map(paramsMap -> paramsMap.get(paramName))
109+
.orElse(null);
110+
}
111+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package net.chrisrichardson.ftgo.restaurantservice.aws;
2+
3+
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
4+
import io.eventuate.javaclient.commonimpl.JSonMapper;
5+
6+
import java.nio.charset.StandardCharsets;
7+
import java.util.Base64;
8+
import java.util.Collections;
9+
import java.util.HashMap;
10+
import java.util.Map;
11+
12+
public class ApiGatewayResponse {
13+
private final int statusCode;
14+
private final String body;
15+
private final Map<String, String> headers;
16+
private final boolean isBase64Encoded;
17+
18+
public ApiGatewayResponse(int statusCode, String body, Map<String, String> headers, boolean isBase64Encoded) {
19+
this.statusCode = statusCode;
20+
this.body = body;
21+
this.headers = headers;
22+
this.isBase64Encoded = isBase64Encoded;
23+
}
24+
25+
public int getStatusCode() {
26+
return statusCode;
27+
}
28+
29+
public String getBody() {
30+
return body;
31+
}
32+
33+
public Map<String, String> getHeaders() {
34+
return headers;
35+
}
36+
37+
// API Gateway expects the property to be called "isBase64Encoded" => isIs
38+
public boolean isIsBase64Encoded() {
39+
return isBase64Encoded;
40+
}
41+
42+
public static Builder builder() {
43+
return new Builder();
44+
}
45+
46+
public static class Builder {
47+
private int statusCode = 200;
48+
private Map<String, String> headers = Collections.emptyMap();
49+
private String rawBody;
50+
private Object objectBody;
51+
private byte[] binaryBody;
52+
private boolean base64Encoded;
53+
54+
public Builder setStatusCode(int statusCode) {
55+
this.statusCode = statusCode;
56+
return this;
57+
}
58+
59+
public Builder setHeaders(Map<String, String> headers) {
60+
this.headers = headers;
61+
return this;
62+
}
63+
64+
public Builder setRawBody(String rawBody) {
65+
this.rawBody = rawBody;
66+
return this;
67+
}
68+
69+
public Builder setObjectBody(Object objectBody) {
70+
this.objectBody = objectBody;
71+
return this;
72+
}
73+
74+
public Builder setBinaryBody(byte[] binaryBody) {
75+
this.binaryBody = binaryBody;
76+
setBase64Encoded(true);
77+
return this;
78+
}
79+
80+
public Builder setBase64Encoded(boolean base64Encoded) {
81+
this.base64Encoded = base64Encoded;
82+
return this;
83+
}
84+
85+
public APIGatewayProxyResponseEvent build() {
86+
String body = null;
87+
if (rawBody != null) {
88+
body = rawBody;
89+
} else if (objectBody != null) {
90+
body = JSonMapper.toJson(objectBody);
91+
} else if (binaryBody != null) {
92+
body = new String(Base64.getEncoder().encode(binaryBody), StandardCharsets.UTF_8);
93+
}
94+
APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();
95+
response.setStatusCode(statusCode);
96+
response.setBody(body);
97+
response.setHeaders(headers);
98+
return response;
99+
}
100+
}
101+
102+
public static APIGatewayProxyResponseEvent buildErrorResponse(AwsLambdaError error) {
103+
return ApiGatewayResponse.builder()
104+
.setStatusCode(Integer.valueOf(error.getCode()))
105+
.setObjectBody(error)
106+
.setHeaders(applicationJsonHeaders())
107+
.build();
108+
}
109+
110+
public static Map<String, String> applicationJsonHeaders() {
111+
Map<String, String> headers = new HashMap<>();
112+
headers.put("Content-Type", "application/json");
113+
return headers;
114+
}
115+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package net.chrisrichardson.ftgo.restaurantservice.aws;
2+
3+
public class AwsLambdaError {
4+
private String type;
5+
private String code;
6+
private String requestId;
7+
private String message;
8+
9+
public AwsLambdaError() {
10+
}
11+
12+
public AwsLambdaError(String type, String code, String requestId, String message) {
13+
this.type = type;
14+
this.code = code;
15+
this.requestId = requestId;
16+
this.message = message;
17+
}
18+
19+
public String getType() {
20+
return type;
21+
}
22+
23+
public String getCode() {
24+
return code;
25+
}
26+
27+
public String getRequestId() {
28+
return requestId;
29+
}
30+
31+
public String getMessage() {
32+
return message;
33+
}
34+
}

0 commit comments

Comments
 (0)