~samwhited/mux

3ae41f5ed4cc0a479784a3cbb44404ef378cb448 — Sam Whited 1 year, 1 month ago c280a1c
mux: add normalization to documentation

Also minor tweaks to the examples to make them consistent with the
documentation, for instance, new instances of a router are now named
"serveMux" instead of "m" because it is likely that they will be used
far away from the original declaration and the single letter variable
name will lack context and be confusing.
2 files changed, 56 insertions(+), 10 deletions(-)

M doc.go
M example_test.go
M doc.go => doc.go +51 -5
@@ 2,9 2,9 @@
//
// The multiplexer in this package is capable of routing based on request method
// and a fixed rooted path (/favicon.ico) or subtree (/images/) which may
// include typed path parameters and wildcards (see "URL Parameters").
// include typed path parameters and wildcards.
//
//	m := mux.New(
//	serveMux := mux.New(
//		mux.Handle(http.MethodGet, "/profile/{username string}", http.NotFoundHandler()),
//		mux.HandleFunc(http.MethodGet, "/profile", http.RedirectHandler("/profile/me", http.StatusPermanentRedirect)),
//		mux.Handle(http.MethodPost, "/logout", logoutHandler()),


@@ 31,9 31,6 @@
//
//     /file/{p path}
//
// To retrieve the value of named path parameters see the Param function and the
// examples.
//
// Two paths with different typed variable parameters (including static routes)
// in the same position are not allowed.
// Attempting to register any two of the following routes will panic:


@@ 43,4 40,53 @@
//     /user/{float}/edit
//     /user/{b string}/edit
//     /user/me
//
// When a route is matched, the value of each named path parameter is stored on
// the request context.
// To retrieve the value of named path parameters from within a handler, the
// Param function can be used.
//
//    pinfo := mux.Param(req, "username")
//    fmt.Println("Got username:", pinfo.Raw)
//
// For more information, see the ParamInfo type and the examples.
//
// Normalization
//
// It's common to normalize routes on HTTP servers.
// For example, a username may need to match the Username Case Mapped profile of
// PRECIS (RFC 8265), or the name of an identifier may need to always be lower
// cased.
// This can be tedious and error prone even if you have enough information to
// figure out what path components need to be replaced, and many HTTP routers
// don't even give you enough information to match path components to their
// original route parameters.
// To make this easier, this package provides the Path and WithParam functions.
// WithParam is used to attach a new context to the context tree with
// replacement values for existing route parameters, and Path is used to
// re-render the path from the original route using the request context.
// If the resulting path is different from req.URL.Path, a redirect can be
// issued or some other corrective action can be applied.
//
//	serveMux := mux.New(
//		mux.Handle(http.MethodGet, "/profile/{username string}", func(w http.ResponseWriter, r *http.Request) {
//			username := mux.Param(r, "username")
//			// You probably want to use the Username Case Mapped profile from the
//			// golang.org/x/text/secure/precis package instead.
//			normalized := strings.ToLower(username.Raw)
//			if normalized != username.Raw {
//				r = mux.WithParam(r, username.Name, normalized)
//				newPath, err := mux.Path(r)
//				if err != nil {
//					panic(fmt.Errorf("mux_test: error creating canonicalized path: %w", err))
//				}
//				http.Redirect(w, r, newPath, http.StatusPermanentRedirect)
//				return
//			}
//
//			fmt.Fprintln(w, "The canonical username is:", pinfo.Raw)
//		}),
//	)
//
// For more information, see the examples.
package mux // import "code.soquee.net/mux"

M example_test.go => example_test.go +5 -5
@@ 13,7 13,7 @@ import (
)

func Example_path() {
	m := mux.New(
	serveMux := mux.New(
		mux.HandleFunc("GET", "/sha256/{wildcard path}", func(w http.ResponseWriter, r *http.Request) {
			val := mux.Param(r, "wildcard")
			sum := sha256.Sum256([]byte(val.Raw))


@@ 21,7 21,7 @@ func Example_path() {
		}),
	)

	server := httptest.NewServer(m)
	server := httptest.NewServer(serveMux)
	resp, err := http.Get(server.URL + "/sha256/a/b")
	if err != nil {
		panic(err)


@@ 34,11 34,11 @@ func Example_path() {
}

func Example_normalization() {
	m := mux.New(
	serveMux := mux.New(
		mux.HandleFunc("GET", "/profile/{username string}/personal", func(w http.ResponseWriter, r *http.Request) {
			username := mux.Param(r, "username")
			// You probably want to use the Username Case Mapped profile from the
			// golang.org/x/text/secure/precis package instead of lowercasing.
			// golang.org/x/text/secure/precis package instead.
			normalized := strings.ToLower(username.Raw)

			// If the username is not canonical, redirect.


@@ 57,7 57,7 @@ func Example_normalization() {
		}),
	)

	server := httptest.NewServer(m)
	server := httptest.NewServer(serveMux)
	defer server.Close()

	resp, err := http.Get(server.URL + "/profile/Me/personal")