com.slack.api.bolt.aws_lambda.SlackApiLambdaHandler Maven / Gradle / Ivy
package com.slack.api.bolt.aws_lambda;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.slack.api.bolt.App;
import com.slack.api.bolt.aws_lambda.request.ApiGatewayRequest;
import com.slack.api.bolt.aws_lambda.request.RequestContext;
import com.slack.api.bolt.aws_lambda.response.ApiGatewayResponse;
import com.slack.api.bolt.request.Request;
import com.slack.api.bolt.request.RequestHeaders;
import com.slack.api.bolt.response.Response;
import com.slack.api.bolt.util.SlackRequestParser;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
/**
* The AWS Lambda handler base class. A subclass that inherits this abstract class works as a Lambda handler.
*
* @see AWS Lambda
*/
@Slf4j
public abstract class SlackApiLambdaHandler implements RequestHandler {
private final SlackRequestParser requestParser;
private final App app;
public SlackApiLambdaHandler(App app) {
this.requestParser = new SlackRequestParser(app.config());
this.app = app;
app.start();
}
/**
* Returns true if the given incoming request is an internal warmup request.
* You can use your own logic for distinguishing requests from Slack from your own internal warmup trigger.
*/
protected abstract boolean isWarmupRequest(ApiGatewayRequest awsReq);
@Override
public ApiGatewayResponse handleRequest(ApiGatewayRequest input, Context context) {
if (isWarmupRequest(input)) {
// This one is always an internal request
// (It's not possible to create this request body via API Gateway)
log.info("Successfully responded to a warmup request ({})", input);
return null;
}
Request> req = toSlackRequest(input);
try {
if (req == null) {
return ApiGatewayResponse.builder().statusCode(400).rawBody("Invalid Request").build();
}
return toApiGatewayResponse(app.run(req));
} catch (Exception e) {
log.error("Failed to respond to a request (request: {}, error: {})", input.getBody(), e.getMessage(), e);
// As this response body can be exposed, it should not have detailed information.
return ApiGatewayResponse.builder().statusCode(500).rawBody("Internal Server Error").build();
}
}
// -------------------------------------------
// Extensible internal methods
// -------------------------------------------
/**
* Returns the underlying {@link App} instance in this handler.
*/
protected App app() {
return app;
}
protected Request> toSlackRequest(ApiGatewayRequest awsReq) {
if (log.isDebugEnabled()) {
log.debug("AWS API Gateway Request: {}", awsReq);
}
RequestContext context = awsReq.getRequestContext();
String body = (awsReq.isBase64Encoded()) ? new String(Base64.getDecoder().decode(awsReq.getBody())) : awsReq.getBody();
SlackRequestParser.HttpRequest rawRequest = SlackRequestParser.HttpRequest.builder()
.requestUri(awsReq.getPath())
.queryString(toStringToStringListMap(awsReq.getQueryStringParameters()))
.headers(new RequestHeaders(toStringToStringListMap(awsReq.getHeaders())))
.requestBody(body)
.remoteAddress(context != null && context.getIdentity() != null ? context.getIdentity().getSourceIp() : null)
.build();
return requestParser.parse(rawRequest);
}
protected ApiGatewayResponse toApiGatewayResponse(Response slackResp) {
return ApiGatewayResponse.builder()
.statusCode(slackResp.getStatusCode())
.headers(toStringToStringMap(slackResp.getHeaders()))
.rawBody(slackResp.getBody())
.build();
}
// -------------------------------------------
// Private utility methods
// -------------------------------------------
private static Map toStringToStringMap(Map> stringToStringListMap) {
Map headers = new HashMap<>();
for (Map.Entry> each : stringToStringListMap.entrySet()) {
if (each.getValue() != null && each.getValue().size() > 0) {
headers.put(each.getKey(), each.getValue().get(0)); // set the first value in the array
}
}
return headers;
}
private static Map> toStringToStringListMap(Map stringToStringListMap) {
if (stringToStringListMap == null) {
return Collections.emptyMap();
}
Map> results = new HashMap<>();
for (Map.Entry each : stringToStringListMap.entrySet()) {
results.put(each.getKey(), Arrays.asList(each.getValue()));
}
return results;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy