Documentation
¶
Overview ¶
Package mux provides helpers for middleware and route handling.
Index ¶
- func AddSpan(ctx context.Context, spanName string, keyValues ...attribute.KeyValue) (context.Context, trace.Span)
- func GetTraceID(ctx context.Context) string
- func SetStatusCode(ctx context.Context, statusCode int)
- type App
- func (a *App) Delete(path string, fn Handler, mw ...Middleware)
- func (a *App) Get(path string, fn Handler, mw ...Middleware)
- func (a *App) Group() *App
- func (a *App) Handle(method, group, path string, handler Handler, mw ...Middleware)
- func (a *App) HandleNoMiddleware(method, group, path string, handler Handler)
- func (a *App) HandleRaw(method, group, path string, handler http.Handler, mw ...Middleware)
- func (a *App) Mount(subRoute string) *App
- func (a *App) Patch(path string, fn Handler, mw ...Middleware)
- func (a *App) Post(path string, fn Handler, mw ...Middleware)
- func (a *App) Put(path string, fn Handler, mw ...Middleware)
- func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (a *App) Use(mw ...Middleware)
- type BaseValues
- type Handler
- type Middleware
- type Option
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AddSpan ¶
func AddSpan(ctx context.Context, spanName string, keyValues ...attribute.KeyValue) (context.Context, trace.Span)
AddSpan adds a span to the tracer, returning it and the context.
func GetTraceID ¶
GetTraceID retrieves the current trace ID from the BaseValue in the given context. We return an empty uuid for testing purposes if not set.
func SetStatusCode ¶
SetStatusCode updates the BaseValue's status code.
Types ¶
type App ¶
type App struct {
// contains filtered or unexported fields
}
App is the core web application, managing routing and middleware.
func New ¶
New creates an App with the given options. A no-op tracer and the default slog logger are used unless overridden via options.
Example ¶
package main
import (
"context"
"fmt"
"log/slog"
"net/http"
"net/http/httptest"
"github.com/adamwoolhether/httper/web/mux"
)
func main() {
app := mux.New(
mux.WithLogger(slog.Default()),
)
app.Get("/health", func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
fmt.Fprint(w, "ok")
return nil
})
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/health", nil)
app.ServeHTTP(w, r)
fmt.Println(w.Body.String())
}
Output: ok
func (*App) Delete ¶
func (a *App) Delete(path string, fn Handler, mw ...Middleware)
Delete registers a handler for DELETE requests at the given path.
func (*App) Get ¶
func (a *App) Get(path string, fn Handler, mw ...Middleware)
Get registers a handler for GET requests at the given path.
Example ¶
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"github.com/adamwoolhether/httper/web/mux"
)
func main() {
app := mux.New()
app.Get("/hello", func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
fmt.Fprint(w, "hello world")
return nil
})
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
app.ServeHTTP(w, r)
fmt.Println(w.Code)
fmt.Println(w.Body.String())
}
Output: 200 hello world
func (*App) Group ¶
Group returns a new App that shares the same underlying ServeMux and tracer but has an independent middleware stack.
Example ¶
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"github.com/adamwoolhether/httper/web/mux"
)
func main() {
app := mux.New()
// Create a group with an independent middleware stack.
api := app.Group()
api.Use(func(handler mux.Handler) mux.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
w.Header().Set("X-API", "true")
return handler(ctx, w, r)
}
})
api.Get("/api/data", func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
fmt.Fprint(w, "data")
return nil
})
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/api/data", nil)
app.ServeHTTP(w, r)
fmt.Println(w.Header().Get("X-API"))
fmt.Println(w.Body.String())
}
Output: true data
func (*App) Handle ¶
func (a *App) Handle(method, group, path string, handler Handler, mw ...Middleware)
func (*App) HandleNoMiddleware ¶
HandleNoMiddleware registers a handler without wrapping it in the route-level or group-level middleware stack.
func (*App) HandleRaw ¶
func (a *App) HandleRaw(method, group, path string, handler http.Handler, mw ...Middleware)
func (*App) Mount ¶
Mount returns a new App scoped to the given sub-route prefix. All routes registered on the returned App are prefixed with subRoute.
Example ¶
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"github.com/adamwoolhether/httper/web/mux"
)
func main() {
app := mux.New()
v1 := app.Mount("/v1")
v1.Get("/users", func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
fmt.Fprint(w, "v1 users")
return nil
})
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/v1/users", nil)
app.ServeHTTP(w, r)
fmt.Println(w.Body.String())
}
Output: v1 users
func (*App) Patch ¶
func (a *App) Patch(path string, fn Handler, mw ...Middleware)
Patch registers a handler for PATCH requests at the given path.
func (*App) Post ¶
func (a *App) Post(path string, fn Handler, mw ...Middleware)
Post registers a handler for POST requests at the given path.
Example ¶
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"github.com/adamwoolhether/httper/web/mux"
)
func main() {
app := mux.New()
app.Post("/items", func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
w.WriteHeader(http.StatusCreated)
fmt.Fprint(w, "created")
return nil
})
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodPost, "/items", nil)
app.ServeHTTP(w, r)
fmt.Println(w.Code)
fmt.Println(w.Body.String())
}
Output: 201 created
func (*App) Put ¶
func (a *App) Put(path string, fn Handler, mw ...Middleware)
Put registers a handler for PUT requests at the given path.
func (*App) ServeHTTP ¶
func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler, wrapping global middleware before serving the request.
func (*App) Use ¶
func (a *App) Use(mw ...Middleware)
Use appends the given middleware to the underlying mw stack.
Example ¶
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"github.com/adamwoolhether/httper/web/mux"
)
func main() {
app := mux.New()
app.Use(func(handler mux.Handler) mux.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
w.Header().Set("X-Custom", "active")
return handler(ctx, w, r)
}
})
app.Get("/ping", func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
fmt.Fprint(w, "pong")
return nil
})
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/ping", nil)
app.ServeHTTP(w, r)
fmt.Println(w.Header().Get("X-Custom"))
fmt.Println(w.Body.String())
}
Output: active pong
type BaseValues ¶
BaseValues represents values that are shared across all requests for logging.
func GetValues ¶
func GetValues(ctx context.Context) *BaseValues
GetValues retrieves the BaseValues from the given context.
type Middleware ¶
Middleware defines a signature to chain Handler together.
type Option ¶
type Option func(*options)
func WithLogger ¶
WithLogger sets the logger used by the App for internal errors.
func WithMiddleware ¶
func WithMiddleware(mw ...Middleware) Option
WithMiddleware auto-categorizes the given middleware by function name, assigns priorities, and splits them into global vs route-level stacks. Known global middleware (CORS, CSRF) runs on every request via ServeHTTP. Known route middleware (Logger, Errors, Panics) and any custom middleware run per-route in priority order.
Example ¶
package main
import (
"fmt"
"log/slog"
"github.com/adamwoolhether/httper/web/middleware"
"github.com/adamwoolhether/httper/web/mux"
)
func main() {
// WithMiddleware auto-categorizes by function name:
// CORS → global, Logger/Errors → route-level, Panics → outermost route-level.
app := mux.New(
mux.WithMiddleware(
middleware.CORS([]string{"*"}),
middleware.Logger(slog.Default()),
middleware.Errors(slog.Default()),
middleware.Panics(),
),
)
_ = app
fmt.Println("middleware auto-categorized")
}
Output: middleware auto-categorized
func WithStaticFS ¶
WithStaticFS serves static files from fsys under the given URL path prefix. The prefix is stripped before looking up files in fsys.
Example ¶
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"testing/fstest"
"github.com/adamwoolhether/httper/web/mux"
)
func main() {
static := fstest.MapFS{
"hello.txt": &fstest.MapFile{Data: []byte("static content")},
}
app := mux.New(
mux.WithStaticFS(static, "/static/"),
)
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/static/hello.txt", nil)
app.ServeHTTP(w, r)
fmt.Println(w.Code)
fmt.Println(w.Body.String())
}
Output: 200 static content
func WithTracer ¶
WithTracer injects the given tracer into the App.