I'm trying to get my routes to redirect the root path to some other path
I have
val route: Route =
pathEnd {
redirect("/browse/master/", StatusCodes.PermanentRedirect)
}
but when I try to go to localhost:8080 (with no subsequent URL segments) it gives me a 404
path(Slash) behaves similarly
Apparently this is meant to work, but doesn't. @ktoso suggested this workaround:
@lihaoyi hm... funky edge case :~ we're using rawPathPrefix there which seems to consume too much hm, could you open a ticket for it?
this will work though:path(PathMatchers.PathEnd) {
pathEnd is mostly used inside other routes to see "ok, no more path elements", perhaps we missed something on the root level and its behaviour hm
This is the ticket requested =)
Hi @lihaoyi, good to have you here :)
Have you tried using pathSingleSlash?
I think what you see is expected behavior. Empty URI paths are not allowed for http, the shortest possible http URI is one with a single slash. That's because the HTTP request line cannot contain an empty path (the shortest is GET / HTTP/1.1).
So let's make this into a documentation ticket to better distinguish path directives in the documentation. Here's a list of differences between path directives that could maybe be better documented:
rawPathPrefix(x) -> x (most basic, matches x and may leave a suffix unmatched)
pathPrefix(x) -> Slash ~ x (matches a leading slash, then x, and then leaves a suffix unmatched)
path(x) -> Slash ~ x ~ PathEnd
pathEnd -> PathEnd (doesn't make sense at the root because an `http://` URI always consists of at least a single slash
pathSingleSlash -> Slash ~ PathEnd
pathEndOrSingleSlash -> PathEnd or Slash ~ PathEnd
Here are some examples:
path("abc") -> Slash ~ Segment("abc") ~ PathEnd -> /abc
pathPrefix("abc") -> Slash ~ Segment("abc") -> /abc + any suffix
path(Slash) -> Slash ~ Slash ~ PathEnd -> //
path(PathMatchers.PathEnd) -> Slash ~ PathEnd -> /
path("") -> Slash ~ PathEnd -> /
So, there are multiple ways to achieve the same. Which if you think about it makes sense because it all composes from the same basic building blocks.
In general, the overall route structure usually looks like this:
pathSingleSlash { // root path
} ~
path("abc") { // "/abc"
} ~
pathPrefix("users") { // use `pathPrefix` to nest hierarchically
path("john") { // "/users/john"
} ~
pathEnd { // "/users"
} ~
pathSingleSlash { // "/users/"
} ~
/* alternatively
pathEndOrSingleSlash { // handles both "/users" or "/users/"
} ~
*/
}
Does that explain the logic?
I can add this information on the pathEnd directive documentation path.
Can you add it to the PathDirectives overview and link to it from all of the mentioned directives?
Sure! I won't be able to do it till the evening (CET), though
We added some more easier to understands docs on it see #563 - thanks @jlprat !
Most helpful comment
We added some more easier to understands docs on it see #563 - thanks @jlprat !