Java: Request Dispatcher

In one of the previous posts i mentioned about AWS there was ‘Request dispatcher’ presented very briefly.

Here I would like to spend a few minutes to write about it in more details.

This is all we need to create the ‘request dispatcher’:

java-request-dispatcher-project-view

Let’s begin with simple POJO that will provide us the Token and Url-Path – the ‘DispatchRequest.java’:

public class DispatchRequest {

    private String path;
    private String token;

    public DispatchRequest() {
    }

    public DispatchRequest(String path, String token) {
        this.path = path;
        this.token = token;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }
}<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>

We also might need some execution context as we needed in AWS Lambda implementation. This may or may not be neccessary depanding on the project.

In this implementation the execution context holds all system environments passed from main Lambda function.

public class DispatchContext {

    private final String property1;
    private final String property2;
    private final String property3;
    private final String property4;
    private final String property5;
    private final String property6;
    private final String property7;
    private final String property8;
    private final String property9;
}

Along with the context it is convinient to have a builder to ease the creation of the DispatchContext object.

Finally, we have the main service that dispatches the execution upon the provided TOKEN and PATH:

import com.fasterxml.jackson.databind.ObjectMapper;
import io.vavr.API;
import io.vavr.control.Try;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class RequestDispatcher {

    private static final Logger log = LogManager.getLogger(RequestDispatcher.class);

    private String apiVersion;

    public Try dispatch(DispatchContext dispatchContext, DispatchRequest dispatchRequest, OutputStream os) {
        final String token = dispatchRequest.getToken();
        final String bucket = dispatchContext.getBucketWithInputData();
        final ObjectMapper om = new ObjectMapper();

        return
            API.Match(dispatchRequest.getPath()).of(
                //@formatter:off
                API.Case(API.$("/" + apiVersion + "/healthcheck"),               () -> runHealthCheck(dispatchContext, os, om)),
                API.Case(API.$("/" + apiVersion + "/configuration"),             () -> runConfiguration(dispatchContext, os)),
                API.Case(API.$("/" + apiVersion + "/resource-1"),                () -> authorize(token).andThenTry(() -> runResource1(bucket,  dispatchContext(), os))),
                API.Case(API.$("/" + apiVersion + "/resource-2"),                () -> authorize(token).andThenTry(() -> runResource2(bucket,  dispatchContext(), os))),
                API.Case(API.$("/" + apiVersion + "/resource-2/sub-resource-1"), () -> authorize(token).andThenTry(() -> runResource21(bucket, dispatchContext(), os))),
                API.Case(API.$("/" + apiVersion + "/resource-2/sub-resource-2"), () -> authorize(token).andThenTry(() -> runResource22(bucket, dispatchContext(), os))),
                API.Case(API.$(), () -> Try.failure(new UnsupportedEndpointException(dispatchRequest.getPath())))
                //@formatter:on
            );
    }
}

Of course, this could be implemented in a lot of different ways. Moreover this is a simplified version due to the fact that AWS API-Gateway takes the responsibility for generating the HTTP responses i.e. 200 CODE. If the dispatcher had to deal with the generation of the full HTTP request it would have gotten more complicated.

Anyways, I like the implementation as it is clear and neat, in my opinion.

 

Advertisements