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:
- /routes/noparam
- /routes/strings/this-is-the-name
- /routes/numbers/42
- /routes/numbers/hello (returns 404 as it's not a number)
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.