Use Java Spark after filter to run custom action when a 404 happens
Asked Answered
H

2

6

I'll try to keep it short. Here's the problem I'm having while trying to understand Spark filters. I'm trying to create a simple app and one of the things that it should do is to create an error report every time the client is about to see an http error e.g. 404 or 500. Here's how my app looks like:

import static spark.Spark.*;

public class MyApp {
    public static void main(String[] args) {
        get("/hello", (req, res) -> "{\"status\":\"OK\"}");

        after((request, response) -> {
            if (response.raw().getStatus() == 404) {
                // here run the code that will report the error e.g. 
                System.out.println("An error has occurred!!");
            }
        });
    }
}

For some reason, the response parameter has its status attribute set to 0 when I'm checking if it's set to 404. The documentation says "after" filters are evaluated after each request and can read the request and read/modify the response so, I should be able to do it somehow (unless the docs are wrong).

Basically, I'm trying to intercept http errors using an after filter but when I try to check the response I don't get what I expect.

Has anyone an idea what would be a different way of doing the same thing or how to make this work?

Thanks.

Hyozo answered 20/11, 2014 at 23:15 Comment(0)
H
6

I solved this one using wildcard routes. Instead of calling the after method, I added a route for each of the HTTP methods that binds the "*" route.

It's important to have them at the bottom of the your Main method so if no route gets resolved these ones always get triggered.

Here's an example:

import static spark.Spark.*;

public class MyApp {
    public static void main(String[] args) {
        get("/hello", (req, res) -> "{\"status\":\"OK\"}");

        get("*", (request, response) -> {
            System.out.println("404 not found!!");
            // email me the request details ...    
        );
    }
}
Hyozo answered 1/12, 2014 at 20:30 Comment(5)
This way will kill static file loadingBekki
No, it won't, @KenBlock. Spark loops through all resource handlers before running the routes. If an internal/external resource is found, Spark will output it and return. This can be seen in spark.servlet.SparkFilter.doFilter github.com/perwendel/spark/blob/master/src/main/java/spark/…Fehr
@TravisSpencer it kills my static file loading...but the 404s work...so close...do you have a working example?Trant
Afraid not (any more at least).Fehr
This doesn't work if you add endpoints at run-time since it has to be the last one. I emailed the team to see if there is an alternative. The only possible workaround I can think of is to do it outside Spark in a proxy by intercepting 404 response and redirect it back to Spark endpoint to handle it.Sonni
F
2

The preferred manner to achieve what you are looking for would look like this.

get("/hello", (request, response) -> {
    // look up your resource using resourceId in request/path/query
    // oh dear, resource not found
    throw new NotFoundException(resourceId);
});

exception(NotFoundException.class, (e, request, response) -> {
    response.status(404);
    response.body(String.format("Resource {%s} not found", e.getResourceId()));
    // doReporting here.
});

public class NotFoundException extends Exception {
    private final String resourceId;
    public NotFoundException(String resourceId) {
        this.resourceId = resourceId;
    }

    public String getResourceId() {
        return resourceId;
    }
}
Floccule answered 19/10, 2015 at 6:42 Comment(4)
whats the actual code syntax for using a resourceId...i cant find that in the documentationTrant
ResourceId and the domain specific Exception class NotFoundException is specific to your domain, not Spark-Java.Floccule
What is specific to Spark-Java is the exception paradigm, which allows for a consistent response for each type of exception. The only debate would be is this a good use of exceptions; that is, is resource not found an exceptional case or is it an expected response.Floccule
This works fine. You might have to cast ((NotFoundException)e).getResourceId() in the exception handler. I had to.Eisler

© 2022 - 2024 — McMap. All rights reserved.