Skip to content

Instantly share code, notes, and snippets.

@jamsesso
Created February 26, 2020 13:31
Show Gist options
  • Save jamsesso/b52743886a9e23227ea933775ca5965f to your computer and use it in GitHub Desktop.
Save jamsesso/b52743886a9e23227ea933775ca5965f to your computer and use it in GitHub Desktop.
Thin lambda dev server
import com.amazonaws.services.lambda.runtime.Context;
import io.javalin.Javalin;
import io.javalin.http.HandlerType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class ApiGatewayServer implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(ApiGatewayServer.class);
private final LambdaApplication app;
private final int port;
private Javalin javalin;
public ApiGatewayServer(LambdaApplication app, int port) {
this.app = app;
this.port = port;
}
public void start() {
javalin = Javalin.create().start("0.0.0.0", port);
for (Class<? extends LambdaFunction> function : app.getFunctions()) {
Lambda metadata = function.getAnnotation(Lambda.class);
HandlerType method = HandlerType.valueOf(metadata.method().toUpperCase());
String path = convertToJavalinPath(metadata.path());
LOG.info("{} /{} ({})", method, metadata.path(), function.getCanonicalName());
javalin.addHandler(method, path, ctx -> {
// Build the request objects.
Context context = new FakeContext(function);
RequestIdentity identity = new RequestIdentity();
identity.setSourceIp(ctx.ip());
identity.setUserAgent(ctx.userAgent());
RequestContext requestContext = new RequestContext();
requestContext.setAccountId("0123456789");
requestContext.setRequestId(context.getAwsRequestId());
requestContext.setStage("local");
requestContext.setIdentity(identity);
Request request = new Request();
request.setBase64Encoded(false);
request.setBody(ctx.body());
request.setHeaders(ctx.headerMap());
request.setHttpMethod(method.name());
request.setPath(ctx.path());
request.setPathParameters(ctx.pathParamMap());
request.setQueryStringParameters(ctx.queryParamMap().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().get(0))));
request.setRequestContext(requestContext);
// Invoke the handler class.
LambdaLauncher launcher = new LambdaLauncher(function, app.module());
Response response = launcher.handleRequest(request, context);
// Write the result to the Javalin context.
for(Map.Entry<String, String> header : response.getHeaders().entrySet()) {
ctx.header(header.getKey(), header.getValue());
}
ctx.status(response.getStatusCode());
ctx.result(response.getBody());
});
}
// This method does not return.
while (!Thread.currentThread().isInterrupted());
}
@Override
public void close() {
if (javalin != null) {
javalin.stop();
}
}
private static String convertToJavalinPath(String apiGatewayPath) {
Pattern pattern = Pattern.compile("\\{(?<VARIABLE>[^{}]+)}");
return pattern.matcher(apiGatewayPath).replaceAll(":$1");
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Lambda {
String path();
String method();
String name() default "";
String description() default "";
int memoryMb() default 128;
int timeoutSec() default 60;
}
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
public interface LambdaFunction extends RequestHandler<Request, Response> {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment