Documentation
¶
Overview ¶
Package httpprefix provides small helpers for mounting net/http handlers under a configurable URL prefix.
Typical use-case: your service can run at root in local/dev, but under a sub-path in production (for example behind a reverse proxy).
The package exposes:
- NormalizeRoutePrefix: converts user-configurable values into a canonical prefix ("" or "/prefix")
- MountUnderPrefix: mounts handlers under that prefix and applies consistent redirect behavior for the bare prefix
- MountUnderPrefixWithOptions: same mount behavior with redirect status code overrides via Option values
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MountUnderPrefix ¶
MountUnderPrefix mounts h under route prefix and returns a handler that serves:
- prefix + "/" subtree via http.StripPrefix(prefix, h)
- bare prefix redirect to prefix + "/"
If prefix normalizes to "", MountUnderPrefix returns h unchanged. This includes empty, whitespace-only, root-like values, and full URLs without a path.
Redirect status is:
- 308 for GET and HEAD
- 307 for all other methods
Prefix normalization inside this function matches NormalizeRoutePrefix:
- full URLs use only their path
- leading slash is added when missing
- trailing slashes are removed
This function uses default redirect status codes (GET/HEAD: 308, others: 307). Use MountUnderPrefixWithOptions to override redirect codes.
Example ¶
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"github.com/containeroo/httpprefix"
)
func main() {
inner := http.NewServeMux()
inner.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
_, _ = io.WriteString(w, "root")
})
inner.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) {
_, _ = io.WriteString(w, "ok")
})
h := httpprefix.MountUnderPrefix(inner, "/app")
rec1 := httptest.NewRecorder()
h.ServeHTTP(rec1, httptest.NewRequest(http.MethodGet, "/app", nil))
fmt.Println(rec1.Code, rec1.Header().Get("Location"))
rec2 := httptest.NewRecorder()
h.ServeHTTP(rec2, httptest.NewRequest(http.MethodGet, "/app/health", nil))
fmt.Println(rec2.Code, rec2.Body.String())
}
Output: 308 /app/ 200 ok
func MountUnderPrefixWithOptions ¶
MountUnderPrefixWithOptions behaves like MountUnderPrefix and accepts optional redirect status code overrides.
If prefix normalizes to "", h is returned unchanged.
Allowed redirect codes are 301, 302, 303, 307, and 308. Invalid codes are replaced with defaults (GET/HEAD: 308, others: 307).
Example ¶
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"github.com/containeroo/httpprefix"
)
func main() {
inner := http.NewServeMux()
inner.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
_, _ = io.WriteString(w, "root")
})
h := httpprefix.MountUnderPrefixWithOptions(
inner,
"/app",
httpprefix.WithGetHeadRedirectCode(http.StatusMovedPermanently), // 301
httpprefix.WithOtherRedirectCode(http.StatusFound), // 302
)
rec1 := httptest.NewRecorder()
h.ServeHTTP(rec1, httptest.NewRequest(http.MethodGet, "/app", nil))
fmt.Println(rec1.Code, rec1.Header().Get("Location"))
rec2 := httptest.NewRecorder()
h.ServeHTTP(rec2, httptest.NewRequest(http.MethodPost, "/app", nil))
fmt.Println(rec2.Code, rec2.Header().Get("Location"))
}
Output: 301 /app/ 302 /app/
func NormalizeRoutePrefix ¶
NormalizeRoutePrefix converts user input into a canonical route prefix.
It accepts either a raw path (for example, "api", "/api", "/api///") or a full URL (for example, "https://example.com/api/").
Rules:
- Empty, whitespace-only, root-like values ("/", "///") return "".
- Trailing slashes are removed.
- A leading slash is added when missing.
- For full URLs, only the URL path is used.
The returned value is always either "" or a string beginning with "/".
Example ¶
package main
import (
"fmt"
"github.com/containeroo/httpprefix"
)
func main() {
fmt.Println(httpprefix.NormalizeRoutePrefix(""))
fmt.Println(httpprefix.NormalizeRoutePrefix("/"))
fmt.Println(httpprefix.NormalizeRoutePrefix("app"))
fmt.Println(httpprefix.NormalizeRoutePrefix("https://example.com/app/"))
}
Output: /app /app
Types ¶
type Option ¶
type Option func(*Options)
Option mutates Options used by MountUnderPrefixWithOptions.
func WithGetHeadRedirectCode ¶
WithGetHeadRedirectCode sets the redirect status code for GET and HEAD requests.
func WithOptions ¶
WithOptions overwrites all redirect options used by MountUnderPrefixWithOptions.
func WithOtherRedirectCode ¶
WithOtherRedirectCode sets the redirect status code for non-GET/HEAD requests.
type Options ¶
type Options struct {
// GetHeadRedirectCode is used for redirects on GET and HEAD requests.
GetHeadRedirectCode int
// OtherRedirectCode is used for redirects on non-GET/HEAD requests.
OtherRedirectCode int
}
Options configures redirect status codes used by MountUnderPrefixWithOptions.