Handlers, Routers and Filters

When a request comes in to the server, it loops through each handler in the order it was added until it finds one that can handle the request. By implementing the MuHandler you can add various types of filters and handlers to your request pipeline.

public class FilterAndStateExample {

    public static void main(String[] args) {
        MuServer server = httpServer()
            .addHandler(new LoggingHandler())
            .addHandler(new HostHeaderChecker())
            .addHandler(new FakeAuthHandler())
            .addHandler(new HelloHandler())
            .start();
        System.out.println("Server started at " + server.uri());
    }

    // Log the request method, path, and IP address
    static class LoggingHandler implements MuHandler {
        public boolean handle(MuRequest request, MuResponse response) {
            System.out.println("Recieved " + request + " from " + request.remoteAddress());
            return false; // so that the next handler is invoked
        }
    }

    // Block any requests where the Host header is not localhost
    static class HostHeaderChecker implements MuHandler {
        public boolean handle(MuRequest request, MuResponse response) {
            if (!request.uri().getHost().equals("localhost")) {
                throw new ClientErrorException("The host header must be 'localhost'", 400);
            }
            return false;
        }
    }

    // Puts a username on the request for subsequent handlers to use
    static class FakeAuthHandler implements MuHandler {
        public boolean handle(MuRequest request, MuResponse response) {
            String username = "bob"; // hard coded for demo
            request.attribute("username", username);
            return false;
        }
    }

    static class HelloHandler implements MuHandler {
        public boolean handle(MuRequest request, MuResponse response) {
            String username = (String)request.attribute("username");
            response.write("Hello, " + username);
            return true;
        }
    }
}
(see full file)

Routing with path parameters

Another way to route requests with a handler is by using the addHandler(Method, String, RouteHandler) method on the MuServerBuilder.

The path template parameter can be accessed in the pathParams in the handler, and the path template uses the same as the JAX-RS path parameters, which means you can restrict matches using regular expressions.

public class RoutingWithPathParams {
    public static void main(String[] args) {
        MuServer server = httpServer()
            .addHandler(Method.GET, "/routes/noparam", (req, resp, pathParams) -> {
                resp.write("No parameters");
            })
            .addHandler(Method.GET, "/routes/strings/{name}", (req, resp, pathParams) -> {
                String name = pathParams.get("name");
                resp.write("The name is: " + name);
            })
            .addHandler(Method.GET, "/routes/numbers/{id : [0-9]+}", (req, resp, pathParams) -> {
                int id = Integer.parseInt(pathParams.get("id"));
                resp.write("The ID is: " + id);
            })
            .start();
        System.out.println("Server started at " + server.uri().resolve("/routes/noparam"));
    }
}
(see full file)

Try it out:

Routing without parameters

A more flexible way to route is to example the request and programmatically decide whether a handler should handle the request or not.

In this case, specify a MuHandler that returns true if the handler will handle the request, or false to allow the next handler in the chain to potentially handle the request.

public class RoutingWithoutPathParams {
    public static void main(String[] args) {
        MuServer server = httpServer()
            .addHandler((req, resp) -> {
                String path = req.uri().getPath();
                if (path.equals("/handle-it") && req.method() == Method.GET) {
                    resp.contentType("text/html");
                    resp.write("This was handled by the <b>handle-it</b> handler");
                    return true;
                } else {
                    return false;
                }
            })
            .addHandler((req, resp) -> {
                resp.contentType("text/html");
                resp.write("This was handled by the <i>catch-all</i> handler");
                return true;
            })
            .start();
        System.out.println("Server started at " + server.uri().resolve("/handle-it"));
    }
}
(see full file)

Annotation-based routing

An alternative to the above methods is to declare paths using the @Path annotation. See the JAX-RS documentation for more info.