Akka-http: High-level server URL redirect on root path doesn't work

Created on 3 Nov 2016  路  5Comments  路  Source: akka/akka-http

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

help wanted docs small

Most helpful comment

We added some more easier to understands docs on it see #563 - thanks @jlprat !

All 5 comments

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 !

Was this page helpful?
0 / 5 - 0 ratings