How to nest routes in Akka HTTP?

I’m trying to write a simple series of routes, here’s what I want to happen:

GET / should print “hello get”

POST / should print “hello post”

GET /foo should print “hello foo get”

POST /foo should print “hello foo get”

Here’s what I have:

val route = pathSingleSlash {
    get(complete("hello get")) ~
    post(complete("hello post"))~
    path("foo") {
      get(complete("hello foo get"))~
      post(complete("hello foo post"))
    }
  }

This works for GET / and POST / but both GET and POST on /foo 404.

I’ve tried almost everything and can’t figure out what to do. The documentation is pretty hard to understand when it comes to this.

Can anyone give me any pointers?

Hi,

Have you seen https://doc.akka.io/docs/akka-http/current/routing-dsl/directives/path-directives/index.html#overview-of-path-directives?

pathSingleSlash only matches a slash at the end of the Uri path.

The path directive on the other side will automatically match a leading slash.

To make it work don’t nest the path(foo) part inside of pathSingleSlash:


pathSingleSlash { get... ~ post } ~

path("foo") { ...}

If you want to nest path directives always use pathPrefix on the outer ones.

Hey Johannes,

If I use the solution you mentioned, wouldn’t I need to declare two variables, one for pathSingleSlash and another for path(“foo”)? But I think you can only pass one route variable when creating/binding the server.

I did think about the pathPrefix, but I wasn’t sure how to do that for the single slash i.e root. Can you do pathPrefix(“/“) or pathPrefix(pathSingleSlash)?

Ideally I’d like to have it like this:

/

get

post

/foo

get

post

/foo/bar

/get

/post

/get and /post at the end there should just be get and post

I think you mean something like this:

val routeToTest = concat(
  pathSingleSlash {
    concat(get(complete("hello get")), 
           post(complete("hello post"))
          )
  },
  pathPrefix("foo") {
    concat(get(complete("hello foo get")), 
           post(complete("hello foo post")),
           path("bar") {
             concat(get(complete("hello foo bar get")),
                    post(complete("hello foo bar post")))
           }
          )
  }
)

Please note that I’m using concat instead of the ~ operator which is less error prone (in my opinion).
And as a nice rule, if you have a path that should have nested paths, use always one of the path methods with prefixin its name. Otherwise, inner paths will never be matched.

Thanks a bunch, Josep.

I also got a good answer on stackoverflow which explains how to use multiple variables to do this: https://stackoverflow.com/a/52475792/49153. I think I’ll use a combo of both options:

Thanks everyone.