perwendel / spark

A simple expressive web framework for java. Spark has a kotlin DSL https://github.com/perwendel/spark-kotlin
Apache License 2.0
9.63k stars 1.56k forks source link

request.matchedPath() returns ALL_PATHS in before and after filters #1180

Open cimi opened 3 years ago

cimi commented 3 years ago

👋

I have a server with before, after and exception filters configured, through which I want to handle logging and metrics. I want to use the value of matchedPath in these filters so I can avoid having repeated logging and metric code in my handlers.

Unfortunately, I'm seeing that request.matchedPath() returns +/*paths (SparkUtils.ALL_PATHS) and not the path that matched inside these filters. I see the same output from all filters (before, after, exception), while the handler returns the correct path. Here's how my setup looks like (simplified):

        get("/api/v1/analysis/:%s", this::handleAnalysis, PROFILE_ID);

        before((request, response) -> {
            LOGGER.info("Before filter");
            debugRequest(request);
            request.attribute("start", Instant.now());
            request.attribute("tagBuilder", new MetricsTagBuilder());
        });

                after(this::logSummaryAndRecordMetric);

        exception(IllegalArgumentException.class, (exception, request, response) -> {
            response.status(400);
            response.body("");
            logSummaryAndRecordMetric(request, response);
        });

                // other exception handlers
14:58:58.278 [qtp1310026465-52] INFO - Before filter
14:58:58.278 [qtp1310026465-52] INFO - Request  url: http://localhost/api/v1/analysis/68ff2cbf-4654-49b6-987a-9c5947b3d599
14:58:58.278 [qtp1310026465-52] INFO - Servlet path: 
14:58:58.278 [qtp1310026465-52] INFO - Context path: null
14:58:58.278 [qtp1310026465-52] INFO - Matched path: +/*paths

14:58:58.279 [qtp1310026465-52] INFO - Inside handler
14:58:58.279 [qtp1310026465-52] INFO - Request  url: http://localhost/api/v1/analysis/68ff2cbf-4654-49b6-987a-9c5947b3d599
14:58:58.279 [qtp1310026465-52] INFO - Servlet path: 
14:58:58.279 [qtp1310026465-52] INFO - Context path: null
14:58:58.279 [qtp1310026465-52] INFO - Matched path: /api/v1/analysis/:profile_id

14:58:58.359 [qtp1310026465-52] INFO - After filter
14:58:58.360 [qtp1310026465-52] INFO - status=200 time= 81ms url='http://localhost/api/v1/analysis/68ff2cbf-4654-49b6-987a-9c5947b3d599' method=GET params='...'
14:58:58.360 [qtp1310026465-52] INFO - Request  url: http://localhost/api/v1/analysis/68ff2cbf-4654-49b6-987a-9c5947b3d599
14:58:58.360 [qtp1310026465-52] INFO - Servlet path: 
14:58:58.360 [qtp1310026465-52] INFO - Context path: null
14:58:58.360 [qtp1310026465-52] INFO - Matched path: +/*paths

Is this a deliberate limitation or a bug? Is there a workaround?

cimi commented 3 years ago

I've made a wrapper for my handlers that sets the matched path as an attribute which I can read from other filters:


        private static void get(String pathTemplate, Route handlerFn, PathParams ... pathParams) {
        var path = buildMatchPath(pathTemplate, pathParams);
        spark.Spark.get(path, wrap(path, handlerFn));
        LOGGER.info("Registered GET handler for {}", path);
    }

    private static Route wrap(String matchedPath, Route handlerFn) {
        return (request, response) -> {
            request.attribute("matchedPath", matchedPath);
            return handlerFn.handle(request, response);
        };
    }

I think this works, but it's hacky. It would be nice if request.matchPath() would be reliable, at least in the after handlers.