Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Look up path parameters by name #20

Open
bowbahdoe opened this issue Nov 21, 2024 · 4 comments
Open

Look up path parameters by name #20

bowbahdoe opened this issue Nov 21, 2024 · 4 comments

Comments

@bowbahdoe
Copy link
Contributor

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

@danielnorberg
Copy link
Owner

danielnorberg commented Nov 21, 2024

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.

@bowbahdoe
Copy link
Contributor Author

bowbahdoe commented Nov 21, 2024

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")

@danielnorberg
Copy link
Owner

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?

@bowbahdoe
Copy link
Contributor Author

Okay opened #21 - we can bikeshed there

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants