eclipse-vertx / vertx-http-proxy

vertx http proxy
Eclipse Public License 2.0
55 stars 36 forks source link

Match interceptor proposal #83

Closed wzy1935 closed 4 months ago

wzy1935 commented 5 months ago

It will add a general match interceptor MatchInterceptor, which can be used to match and transform request and responses among headers, params, body, and HTTP methods.

MatchInterceptor consists of two groups of methods, matchers and transformers. Matchers are used to capture the value in the request or response into the context and to decide if the interceptor itself continue to apply further matchers and transformers. Transformers are used to transform the request and response with the context.

Following is an example about how to use it:

// To put the header "token" into the params and rename it "app_token". These 2 ways are itentical:

// Literals
MatchInterceptor.builder()
    // match header "token" into the context's attachment
    .matchRequestHeaders("token") 
    // put a param named "app_token" with the value of token
    .updateParams("app_token", "$token"); 

// Functionals
MatchInterceptor.builder()
    // match header "token" into the context's attachment
    .matchRequestHeaders((ctx, headers) -> { 
        if (headers.contains("token")) {
            ctx.set("token", headers.get("token"));
            return true;
        }
        return false;
    })
    // put a param named "app_token" with the value of token
    .transformParams((ctx, params) -> { 
        params.set("app_token", ctx.get("token", String.class));
        return params;
    });

Both matchers and transformers can be written in the literal or functional manners. Literals uses mostly String to set up the proxy, which is easy and beneficial for configuration file usages. It use $ for value extraction and injection. Example:

MatchInterceptor.builder()
    .matchPath("api/v1/user/$name") // match the names to the context
    .updatePath("api/v1/user") // transform path
    .updateParams("user", "$name"); // use the name values from the context

Functionals are more flexible. They typically looks like this:

// matcher:
(ProxyContext, T) -> Boolean

// transformer:
(ProxyContext, T) -> T

Matcher fetch values from T to put them into ProxyContext. It return Boolean to decide to continue this interceptor or not.

Transformer transforms T with values in ProxyContext.

Here I use the ProxyContext in the callback parameter because it could be helpful to share contextual data for issue 71. But I'm also worried that this will give user too much control for modifying the context itself. Maybe I should only use the Proxy.attachments map in the callback (I'm assuming that is for contextual data sharing) ?

wzy1935 commented 5 months ago

(Here's part of the implementation. For now I know it's doable, while probably need some suggestions for APIs)

tsegismont commented 4 months ago

Thanks for putting together this proposal.

I'm not sure I'd like to move forward with this because request path/query/etc matching is the job of Vert.x Web. I don't believe we should replicate (even in a reduced scope) the features of that module.

Perhaps, at a later stage of the GSoC project, we can think about how to connect Vert.x Web features with the Proxy features, with enhancement to the vertx-web-proxy project.