How to match, but not consume, a path prefix in Akka HTTP?

Viewed 575

my Akka HTTP application reverse-proxies some requests to an internal HTTP system:

pathPrefix("/api/") {
  (path("some-upload-endpoint") & post) {
    withSizeLimit(10 * 1024 * 1024) {
      reverseProxyToBackend(rc)
    }
  } ~ reverseProxyToBackend(rc)
}

reverseProxyToBackend is a custom directive that takes the incoming requests, adds some headers and forwards it to the backend system, based on the remaining unmatched path. IOW, /api/foobar becomes backend.example.com/foobar.

For a certain path some-upload-endpoint however I need to increase the default size limit of the frontend, as we expect larger requests to this endpoint.

Unfortunately, path("some-upload-endpoint") consumes the remaining path, so with the above code reverseProxyToBackend would forward to backend.example.com rather than backend.example.com/some-upload-endpoint, which is not what I want.

How can I match a path in Akka HTTP, but not consume it? In other words, what directives can I use to keep the unmatched path untouched by a path matcher? And if there's no such directive, how can I restore the unmatched path?

2 Answers

extractMatchedPath should "reconstitute" the path that was already matched. From the documentation:

The extractMatchedPath directive extracts the path that was already matched by any of the PathDirectives (or any custom ones that change the unmatched path field of the request context). You can use it for building directives that use already matched part in their logic.

Adding to Ramon's answer, you can restore the unmatched path using mapRequestContext:

extractMatchedPath { matchedPath =>
  mapRequestContext(_.withUnmatchedPath(matchedPath)) { // reset the "unmatchedPath"
    ...
  }
}

You might also be interested in pathPrefixTest, rawPathPrefixTest, etc. Basically pathPrefixTest is like pathPrefix but it does not "consume" the path segments.

Related