ignoreTrailingSlash

Signature

def ignoreTrailingSlash: Directive0 

Description

If the requested path ends with a trailing / character and the inner route is rejected with an empty RejectionRejection list, it retries the inner route it removing the trailing / character. Similarly, it retries adding a trailing / character if the original requested path doesn’t end with a / character.

This directive will retry the inner route with a “flipped” trailing slash only if the mentioned inner route is rejected with an empty RejectionRejection list.

Note

Please note that enclosing routes with this directive might cause double evaluation in case of unhandled request paths. This may be expensive when enclosing big route trees. Use with care.

See also redirectToNoTrailingSlashIfPresent and redirectToTrailingSlashIfMissing for other ways to accomplish a similar thing.

Example

Scala
sourceval route = ignoreTrailingSlash {
  concat(
    path("foo") {
      // Thanks to `ignoreTrailingSlash` it will serve both `/foo` and `/foo/`.
      complete("OK")
    },
    path("bar"./) {
      // Thanks to `ignoreTrailingSlash` it will serve both `/bar` and `/bar/`.
      complete("OK")
    })
}

// tests:
Get("/foo") ~> route ~> check {
  status shouldEqual StatusCodes.OK
  responseAs[String] shouldEqual "OK"
}

Get("/foo/") ~> route ~> check {
  status shouldEqual StatusCodes.OK
  responseAs[String] shouldEqual "OK"
}

Get("/bar") ~> route ~> check {
  status shouldEqual StatusCodes.OK
  responseAs[String] shouldEqual "OK"
}

Get("/bar/") ~> route ~> check {
  status shouldEqual StatusCodes.OK
  responseAs[String] shouldEqual "OK"
}
Java
sourceimport static org.apache.pekko.http.javadsl.server.Directives.complete;
import static org.apache.pekko.http.javadsl.server.Directives.path;
import static org.apache.pekko.http.javadsl.server.Directives.ignoreTrailingSlash;
final Route route =
    ignoreTrailingSlash(
        () ->
            concat(
                path(
                    "foo",
                    () ->
                        // Thanks to `ignoreTrailingSlash` it will serve both `/foo` and
                        // `/foo/`.
                        complete("OK")),
                path(
                    PathMatchers.segment("bar").slash(),
                    () ->
                        // Thanks to `ignoreTrailingSlash` it will serve both `/bar` and
                        // `/bar/`.
                        complete("OK"))));

// tests:
testRoute(route)
    .run(HttpRequest.GET("/foo"))
    .assertStatusCode(StatusCodes.OK)
    .assertEntity("OK");
testRoute(route)
    .run(HttpRequest.GET("/foo/"))
    .assertStatusCode(StatusCodes.OK)
    .assertEntity("OK");

testRoute(route)
    .run(HttpRequest.GET("/bar"))
    .assertStatusCode(StatusCodes.OK)
    .assertEntity("OK");
testRoute(route)
    .run(HttpRequest.GET("/bar/"))
    .assertStatusCode(StatusCodes.OK)
    .assertEntity("OK");