rut
rut copied to clipboard
Look up path parameters by name
Maybe i'm missing something, but i don't see an easy way to get the value for a path parameter by name instead of by index
Yeah there is no such method because the Result does not store captured parameters in a Map for performance reasons. Indeed it only stores a list of indexes into the original input string.
Here is a utility method one could use to get a parameter by name:
static Optional<CharSequence> paramValueByName(final Router.Result<?> result, final String paramName) {
for (int i = 0; i < result.params(); i++) {
if (result.paramName(i).equals(paramName)) {
return Optional.of(result.paramValue(i));
}
}
return Optional.empty();
}
Use it like this:
final Optional<CharSequence> user = paramValueByName(result, "user");
Arguably we could add this utility method to Result. It is however more efficient for users to store the indexes of parameters e.g. as constants and use those indexes to access the captured values.
Yeah i'm less concerned with absolute maximal efficiency and more with the usage side. Considering routes tend to have relatively few route params I don't think you need a map. The linear scan approach is probably just fine.
The reason I am on this is I just made this library https://github.com/bowbahdoe/jdk-httpserver-rutrouter
void main() {
var router = RutRouter.builder()
.get("/hello/<name>", e -> {
e.getResponseHeaders().put("Content-Type", List.of("text/html"));
e.sendResponseHeaders(200, 0);
var c = RutRouter.result(e);
try (var body = e.getResponseBody()) {
body.write(("<h1>Hiya " + c.paramValueDecoded(0) + " " + c.query() + "</h1>").getBytes(StandardCharsets.UTF_8));
}
})
.notFoundHandler(e -> {
e.getResponseHeaders().put("Content-Type", List.of("text/html"));
e.sendResponseHeaders(404, 0);
try (var body = e.getResponseBody()) {
body.write("<h1>Not Found</h1>".getBytes(StandardCharsets.UTF_8));
}
})
.build();
var server = HttpServer.create(new InetSocketAddress(8783), 0);
server.createContext("/", router);
server.start();
}
As you can see from the example, .paramValueDecoded(0) really doesn't work that well if the route definition and handler are far apart in the code.
i'd prefer to use .paramValueDecoded("name")
Yeah, linear scan is fine and more efficient than a map for most cases.
Sure, we can add paramValueByName and paramValueDecodedByName methods to Result. Would you like to submit a PR?
Okay opened #21 - we can bikeshed there
Would you mind publishing a release with the changes from #21 ?