From 699cc8d825d414019dea454d63bf47bb4bedfa2c Mon Sep 17 00:00:00 2001 From: funwithcthulhu <29905917+funwithcthulhu@users.noreply.github.com> Date: Thu, 21 May 2026 19:09:06 -0700 Subject: [PATCH] Document decoded route literals --- src/dream.mli | 7 +++++++ test/expect/server/router.ml | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/dream.mli b/src/dream.mli index a0383921..a6bbff94 100644 --- a/src/dream.mli +++ b/src/dream.mli @@ -1392,6 +1392,13 @@ val router : route list -> handler request's prefix to be extended by it. It is mainly useful for “mounting” {!Dream.static} as a subsite. + Route paths are matched against the decoded request path. In route + literals, write decoded characters such as ["/photos/södermalm/"], not the + percent-encoded wire form such as ["/photos/s%C3%B6dermalm/"]. The original + target, returned by {!Dream.target} and printed by the logger, remains + percent-encoded so it can be recorded without interpreting arbitrary client + input. + It can also be used as an escape hatch to convert a handler, which may include its own router, into a subsite. However, it is better to compose sites with routes and {!Dream.scope} rather than opaque handlers and [**], diff --git a/test/expect/server/router.ml b/test/expect/server/router.ml index e1122f25..559229a9 100644 --- a/test/expect/server/router.ml +++ b/test/expect/server/router.ml @@ -225,6 +225,17 @@ let%expect_test _ = Response: 200 OK foo |}] +let%expect_test _ = + show "/photos/s%C3%B6dermalm_pride/" @@ Dream.router [ + Dream.get "/photos/s%C3%B6dermalm_pride/" (fun _ -> + Dream.respond "encoded"); + Dream.get "/photos/södermalm_pride/" (fun _ -> + Dream.respond "decoded"); + ]; + [%expect {| + Response: 200 OK + decoded |}] + (* Router matches long paths, does not match prefixes, etc. *) let%expect_test _ =