GH-786 Fix regression with RoutingFunction over AWS APIGateway
Resolves #786
This commit is contained in:
@@ -82,7 +82,7 @@ public class FunctionInvoker implements RequestStreamHandler {
|
|||||||
this.start();
|
this.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
@Override
|
@Override
|
||||||
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
|
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
|
||||||
final byte[] payload = StreamUtils.copyToByteArray(input);
|
final byte[] payload = StreamUtils.copyToByteArray(input);
|
||||||
@@ -99,10 +99,18 @@ public class FunctionInvoker implements RequestStreamHandler {
|
|||||||
|
|
||||||
|
|
||||||
// TODO we should eventually completely delegate to message converter
|
// TODO we should eventually completely delegate to message converter
|
||||||
//Message requestMessage = MessageBuilder.withPayload(payload).setHeader(AWSLambdaUtils.AWS_API_GATEWAY, true).build();
|
Message requestMessage;
|
||||||
Message requestMessage = isApiGateway
|
if (isApiGateway) {
|
||||||
? MessageBuilder.withPayload(payload).setHeader(AWSLambdaUtils.AWS_API_GATEWAY, true).build()
|
MessageBuilder builder = MessageBuilder.withPayload(payload).setHeader(AWSLambdaUtils.AWS_API_GATEWAY, true);
|
||||||
: AWSLambdaUtils.generateMessage(payload, new MessageHeaders(Collections.emptyMap()), function.getInputType(), this.jsonMapper, context);
|
if (structMessage instanceof Map && ((Map) structMessage).containsKey("headers")) {
|
||||||
|
builder.copyHeaders((Map) ((Map) structMessage).get("headers"));
|
||||||
|
}
|
||||||
|
requestMessage = builder.build();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
requestMessage = AWSLambdaUtils
|
||||||
|
.generateMessage(payload, new MessageHeaders(Collections.emptyMap()), function.getInputType(), this.jsonMapper, context);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object response = this.function.apply(requestMessage);
|
Object response = this.function.apply(requestMessage);
|
||||||
@@ -111,15 +119,20 @@ public class FunctionInvoker implements RequestStreamHandler {
|
|||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
logger.error(e);
|
logger.error(e);
|
||||||
StreamUtils.copy(this.buildExceptionResult(requestMessage, e), output);
|
StreamUtils.copy(this.buildExceptionResult(requestMessage, e, isApiGateway), output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] buildExceptionResult(Message<?> requestMessage, Exception exception) throws IOException {
|
private byte[] buildExceptionResult(Message<?> requestMessage, Exception exception, boolean isApiGateway) throws IOException {
|
||||||
APIGatewayProxyResponseEvent event = new APIGatewayProxyResponseEvent();
|
if (isApiGateway) {
|
||||||
event.setStatusCode(HttpStatus.EXPECTATION_FAILED.value());
|
APIGatewayProxyResponseEvent event = new APIGatewayProxyResponseEvent();
|
||||||
event.setBody(exception.getMessage());
|
event.setStatusCode(HttpStatus.EXPECTATION_FAILED.value());
|
||||||
return this.jsonMapper.toJson(event);
|
event.setBody(exception.getMessage());
|
||||||
|
return this.jsonMapper.toJson(event);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalStateException(exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ public class RoutingFunction implements Function<Object, Object> {
|
|||||||
else {
|
else {
|
||||||
throw new IllegalStateException("Failed to establish route, since neither were provided: "
|
throw new IllegalStateException("Failed to establish route, since neither were provided: "
|
||||||
+ "'spring.cloud.function.definition' as Message header or as application property or "
|
+ "'spring.cloud.function.definition' as Message header or as application property or "
|
||||||
+ "'spring.cloud.function.routing-expression' as application property.");
|
+ "'spring.cloud.function.routing-expression' as application property. Incoming message: " + input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,18 +10,17 @@ You can do so in two different ways.
|
|||||||
1. You can provide `spring_cloud_function_definition` environment variable setting its value to the desired function definition, which could also be composition
|
1. You can provide `spring_cloud_function_definition` environment variable setting its value to the desired function definition, which could also be composition
|
||||||
(e.g., `spring_cloud_function_definition=foo|bar`).
|
(e.g., `spring_cloud_function_definition=foo|bar`).
|
||||||
|
|
||||||
2. A more dynamic and recommended approach would be to fallback on auto routing capabilities of spring-cloud function's in AWS environment.
|
|
||||||
Basically every time you have more then one function in your configuration, the framework will bind
|
|
||||||
[Routing Function](https://docs.spring.io/spring-cloud-function/docs/3.1.3/reference/html/spring-cloud-function.html#_function_routing_and_filtering)
|
|
||||||
as AWS Lambda, and all you need to to is provide a routing instruction via Message headers or environment variables. The instructions could themselves be very dynamic,
|
|
||||||
since we support both SpEL and registering a callback interface. For more details on routing mechanisms please refer to
|
|
||||||
[Function Routing and Filtering](https://docs.spring.io/spring-cloud-function/docs/3.1.3/reference/html/spring-cloud-function.html#_function_routing_and_filtering) section.
|
|
||||||
|
|
||||||
|
|
||||||
NOTE: Keep in mind though that since AWS does not allow dots `.` and/or hyphens`-` in the name of the environment variable, you can benefit from boot support and simply substitute
|
NOTE: Keep in mind though that since AWS does not allow dots `.` and/or hyphens`-` in the name of the environment variable, you can benefit from boot support and simply substitute
|
||||||
dots with underscores and hyphens with camel case. So for example `spring.cloud.function.definition` becomes `spring_cloud_function_definition`
|
dots with underscores and hyphens with camel case. So for example `spring.cloud.function.definition` becomes `spring_cloud_function_definition`
|
||||||
and `spring.cloud.function.routing-expression` becomes `spring_cloud_function_routingExpression`.
|
and `spring.cloud.function.routing-expression` becomes `spring_cloud_function_routingExpression`.
|
||||||
|
|
||||||
|
2. A more dynamic and recommended approach would be to fallback on auto routing capabilities of spring-cloud function's in AWS environment.
|
||||||
|
Basically every time you have more then one function in your configuration, the framework will bind
|
||||||
|
[Routing Function](https://docs.spring.io/spring-cloud-function/docs/3.1.3/reference/html/spring-cloud-function.html#_function_routing_and_filtering)
|
||||||
|
as AWS Lambda, and all you need to to is provide a routing instruction via Message headers or environment variables. The instructions could themselves be very dynamic, since we support both SpEL and registering a callback interface. For more details on routing mechanisms please refer to
|
||||||
|
[Function Routing and Filtering](https://docs.spring.io/spring-cloud-function/docs/3.1.3/reference/html/spring-cloud-function.html#_function_routing_and_filtering) section.
|
||||||
|
|
||||||
|
|
||||||
In this example we have configuration with two functions; `uppercase` and `reverse`.
|
In this example we have configuration with two functions; `uppercase` and `reverse`.
|
||||||
When executing from AWS Lambda functions dashboard you can simply provide one of the mentioned properties as environment variables via Configuration tab.
|
When executing from AWS Lambda functions dashboard you can simply provide one of the mentioned properties as environment variables via Configuration tab.
|
||||||
For example, you can set `spring_cloud_function_routingExpression` environment variable with the value of literal; SpEL expression `'uppercase'` (not the single quotes).
|
For example, you can set `spring_cloud_function_routingExpression` environment variable with the value of literal; SpEL expression `'uppercase'` (not the single quotes).
|
||||||
|
|||||||
@@ -33,6 +33,10 @@
|
|||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-function-adapter-aws</artifactId>
|
<artifactId>spring-cloud-function-adapter-aws</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.amazonaws</groupId>
|
<groupId>com.amazonaws</groupId>
|
||||||
|
|||||||
Reference in New Issue
Block a user