Files
sux/README.md

121 lines
2.5 KiB
Markdown
Raw Normal View History

2025-11-25 18:27:01 +01:00
# sux
2021-10-31 09:03:21 +01:00
2025-11-25 18:27:01 +01:00
An allocation-conscious, middleware-capable HTTP router for Go with support for static routes, parameters (`:id`), wildcards (`*path`), route groups, and configurable 404/405 handling.
2021-10-31 09:03:21 +01:00
2025-11-25 18:27:01 +01:00
## Installation
2021-10-31 09:03:21 +01:00
2025-11-25 18:27:01 +01:00
```bash
go get code.icod.de/dalu/sux
```
2021-10-31 09:03:21 +01:00
2025-11-25 18:27:01 +01:00
## Quick start
2021-10-31 09:03:21 +01:00
```go
package main
import (
"net/http"
2025-11-25 18:27:01 +01:00
"code.icod.de/dalu/sux"
2021-10-31 09:03:21 +01:00
)
func main() {
r := sux.New()
2025-11-25 18:27:01 +01:00
r.GET("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello"))
})
r.GET("/users/:id", func(w http.ResponseWriter, r *http.Request) {
params := sux.ParamsFromContext(r)
w.Write([]byte("user " + params.Get("id")))
})
2021-10-31 09:03:21 +01:00
2025-11-25 18:27:01 +01:00
http.ListenAndServe(":8080", r)
2021-10-31 09:03:21 +01:00
}
```
2025-11-25 18:27:01 +01:00
## Middleware
2025-11-25 18:27:01 +01:00
Middleware wraps handlers and can be applied globally or per route group.
2025-11-25 18:27:01 +01:00
```go
logger := func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// log request here
next.ServeHTTP(w, r)
})
}
2025-11-25 18:27:01 +01:00
r := sux.New()
r.Use(logger) // global
2025-11-25 18:27:01 +01:00
r.GET("/ping", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("pong"))
})
```
2025-11-25 18:27:01 +01:00
## Route groups
2025-11-25 18:27:01 +01:00
Groups share a prefix and middleware.
2025-11-25 18:27:01 +01:00
```go
api := r.Group("/api", func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
2025-11-25 18:27:01 +01:00
w.Header().Set("X-API-Version", "v1")
next.ServeHTTP(w, r)
})
2025-11-25 18:27:01 +01:00
})
2025-11-25 18:27:01 +01:00
api.GET("/users", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("users"))
})
```
2025-11-25 18:27:01 +01:00
## Parameters and wildcards
```go
2025-11-25 18:27:01 +01:00
r.GET("/posts/:postId", func(w http.ResponseWriter, r *http.Request) {
p := sux.ParamsFromContext(r)
w.Write([]byte(p.Get("postId")))
})
2025-11-25 18:27:01 +01:00
r.GET("/files/*path", func(w http.ResponseWriter, r *http.Request) {
p := sux.ParamsFromContext(r)
w.Write([]byte("file: " + p.Get("path")))
})
```
2025-11-25 18:27:01 +01:00
## 404/405 handlers
```go
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
2025-11-25 18:27:01 +01:00
http.Error(w, "custom 404", http.StatusNotFound)
})
r.MethodNotAllowed(func(w http.ResponseWriter, r *http.Request) {
2025-11-25 18:27:01 +01:00
http.Error(w, "custom 405", http.StatusMethodNotAllowed)
})
2025-11-25 18:27:01 +01:00
// Disable cross-method probing if you prefer 404s instead of 405 checks
r.EnableMethodNotAllowedCheck(false)
```
2025-11-25 18:27:01 +01:00
## Performance notes
2025-11-25 18:27:01 +01:00
- Internally pools parsed segments and parameter storage to reduce per-request allocations.
- Parameters are copied into the request context so they remain valid even after handlers return (important for async users of the context).
- For raw numbers, run `go test -bench . -benchmem`.
2025-11-25 18:27:01 +01:00
## Testing
2025-11-25 18:27:01 +01:00
```bash
go test ./...
```
2025-11-25 18:27:01 +01:00
Benchmarks:
2025-11-25 18:27:01 +01:00
```bash
go test -bench . -benchmem
```