Files
sux/README.md

244 lines
6.4 KiB
Markdown
Raw Normal View History

2021-10-31 09:03:21 +01:00
# Sux
2025-10-28 00:17:59 +01:00
HTTP router that considers the request method with support for parameters, middleware, and route groups.
2021-10-31 09:03:21 +01:00
2025-10-28 00:17:59 +01:00
Useful for serving all kinds of content.
2021-10-31 09:03:21 +01:00
## Features
- **High Performance**: Optimized trie-based routing with minimal allocations
- **URL Parameters**: Support for `:param` and `*wildcard` parameters
- **Middleware**: Global and route-specific middleware support
- **Route Groups**: Group routes with shared prefixes and middleware
- **Thread-Safe**: No global state - multiple router instances supported
- **Method Not Allowed**: Proper 405 responses when path exists but method doesn't
- **Custom Handlers**: Custom 404 and 405 handlers
2021-10-31 09:03:21 +01:00
## How
### Basic Usage
2021-10-31 09:03:21 +01:00
```go
package main
import (
2022-10-18 12:26:16 +02:00
"code.icod.de/dalu/sux"
2021-10-31 09:03:21 +01:00
"io"
"net/http"
)
func main() {
r := sux.New()
r.GET("/", Hello)
r.GET("/simple", Simple)
http.ListenAndServe(":8080", r)
}
func Hello(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hello")
}
func Simple(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
io.WriteString(w, "hello "+name)
}
```
### URL Parameters
```go
r := sux.New()
// Named parameters
r.GET("/users/:id", func(w http.ResponseWriter, r *http.Request) {
params := sux.ParamsFromContext(r)
id := params["id"]
io.WriteString(w, "User ID: "+id)
})
// Wildcard parameters (captures rest of path)
r.GET("/files/*path", func(w http.ResponseWriter, r *http.Request) {
params := sux.ParamsFromContext(r)
path := params["path"]
io.WriteString(w, "File path: "+path)
})
// Multiple parameters
r.GET("/users/:userId/posts/:postId", func(w http.ResponseWriter, r *http.Request) {
params := sux.ParamsFromContext(r)
userId := params["userId"]
postId := params["postId"]
io.WriteString(w, "User "+userId+", Post "+postId)
})
```
### Middleware
```go
r := sux.New()
// Global middleware
r.Use(loggingMiddleware, authMiddleware)
// Route-specific middleware
r.GET("/admin", adminOnlyMiddleware(adminHandler))
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
})
}
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Check authentication
if !isAuthenticated(r) {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
```
### Route Groups
```go
r := sux.New()
// API group with middleware
api := r.Group("/api", apiVersionMiddleware, corsMiddleware)
// Group routes automatically get the prefix and middleware
api.GET("/users", listUsers)
api.POST("/users", createUser)
api.GET("/users/:id", getUser)
// Nested groups
v1 := api.Group("/v1")
v1.GET("/posts", listPostsV1)
v2 := api.Group("/v2")
v2.GET("/posts", listPostsV2)
```
### Custom Handlers
```go
r := sux.New()
// Custom 404 handler
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte("Custom 404 - Page not found"))
})
// Custom 405 handler
r.MethodNotAllowed(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusMethodNotAllowed)
w.Write([]byte("Custom 405 - Method not allowed"))
})
```
### Multiple Router Instances
```go
// Each router is independent and thread-safe
mainRouter := sux.New()
mainRouter.GET("/", homeHandler)
apiRouter := sux.New()
apiRouter.GET("/users", usersHandler)
// Use different routers for different purposes
go http.ListenAndServe(":8080", mainRouter)
go http.ListenAndServe(":8081", apiRouter)
```
## Performance
The router is optimized for high performance with hash map-based O(1) child lookups and zero-allocation optimizations:
```
BenchmarkStaticRoute-8 1859550 682.1 ns/op 740 B/op 10 allocs/op
BenchmarkParameterRoute-8 1538643 868.9 ns/op 704 B/op 9 allocs/op
BenchmarkWildcardRoute-8 1281626 979.3 ns/op 736 B/op 10 allocs/op
BenchmarkMultipleParameters-8 1000000 1026 ns/op 768 B/op 9 allocs/op
BenchmarkMiddleware-8 567559 1930 ns/op 1568 B/op 19 allocs/op
BenchmarkRouteGroups-8 867961 1442 ns/op 1480 B/op 15 allocs/op
BenchmarkLargeRouter-8 1548286 833.0 ns/op 704 B/op 9 allocs/op
```
**Performance Improvements:**
- Static routes: 14.6% faster (682.1 vs 798.5 ns/op)
- Parameter routes: 24.7% faster (868.9 vs 1154 ns/op)
- Wildcard routes: 41.6% faster (979.3 vs 1676 ns/op)
- Multiple parameters: 41.5% faster (1026 vs 1753 ns/op)
- Middleware: 49.0% faster (1930 vs 3782 ns/op)
- Route groups: 49.5% faster (1442 vs 2855 ns/op)
- Large router: 24.5% faster (833.0 vs 1103 ns/op)
**Memory Allocation Improvements:**
- Optimized parameter handling with slice-based storage
- Zero-allocation path parsing for common cases
- Enhanced memory pooling for frequently used objects
- String builder optimization for wildcard parameters
### Performance Comparison
2025-10-28 00:17:59 +01:00
see [COMPARISON.md](COMPARISON.md)
2021-10-31 09:03:21 +01:00
## API Reference
2021-10-31 09:03:21 +01:00
### Router Methods
- `New() *Router` - Creates a new router instance
- `GET(path string, handler http.HandlerFunc) *Router`
- `POST(path string, handler http.HandlerFunc) *Router`
- `PUT(path string, handler http.HandlerFunc) *Router`
- `PATCH(path string, handler http.HandlerFunc) *Router`
- `DELETE(path string, handler http.HandlerFunc) *Router`
- `OPTIONS(path string, handler http.HandlerFunc) *Router`
- `HEAD(path string, handler http.HandlerFunc) *Router`
### Middleware
- `Use(middleware ...MiddlewareFunc)` - Add global middleware
- `Group(prefix string, middleware ...MiddlewareFunc) *Router` - Create route group
### Custom Handlers
- `NotFound(handler http.HandlerFunc)` - Set custom 404 handler
- `MethodNotAllowed(handler http.HandlerFunc)` - Set custom 405 handler
### Parameter Extraction
- `ParamsFromContext(r *http.Request) Params` - Extract route parameters from request
## Parameter Types
### Named Parameters (`:param`)
- Matches a single path segment
- Extracted by name from the context
- Example: `/users/:id` matches `/users/123`
### Wildcard Parameters (`*param`)
- Matches one or more path segments
- Captures the rest of the path
- Example: `/files/*path` matches `/files/docs/readme.txt`
## Thread Safety
The router is completely thread-safe:
2021-10-31 09:03:21 +01:00
- No global state
- Multiple router instances can be used concurrently
- Safe for concurrent use from multiple goroutines
2021-10-31 09:03:21 +01:00
## License
2021-10-31 09:03:21 +01:00
MIT License - see LICENSE file for details.