### Example: Create and Use Fox Router (Go) Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md This example demonstrates how to create a simple router using the default options, which include the Recovery and Logger middleware. It defines a GET route for '/hello/{name}' and starts an HTTP server. ```go // Create a new router with default options, which include the Recovery and Logger middleware r, _ := New(DefaultOptions()) // Define a route with the path "/hello/{name}", and set a simple handler that greets the // user by their name. r.MustHandle(http.MethodGet, "/hello/{name}", func(c Context) { _ = c.String(200, "Hello %s\n", c.Param("name")) }) // Start the HTTP server using fox router and listen on port 8080 log.Fatalln(http.ListenAndServe(":8080", r)) ``` -------------------------------- ### Basic HTTP Server with Fox Router Source: https://github.com/tigerwill90/fox/blob/master/README.md Demonstrates how to initialize a new Fox router instance, register a GET route with a named parameter, and start an HTTP server. It shows basic request handling and parameter extraction from the URL path. ```go package main import ( "errors" "github.com/tigerwill90/fox" "log" "net/http" ) func main() { f, err := fox.New(fox.DefaultOptions()) if err != nil { panic(err) } f.MustHandle(http.MethodGet, "/hello/{name}", func(c fox.Context) { _ = c.String(http.StatusOK, "hello %s\n", c.Param("name")) }) if err := http.ListenAndServe(":8080", f); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalln(err) } } ``` -------------------------------- ### Install Fox Go HTTP Router Source: https://github.com/tigerwill90/fox/blob/master/README.md This command installs the Fox HTTP router package for Go using the `go get` tool. It fetches the latest version of the library and adds it to your Go module dependencies. ```Shell go get -u github.com/tigerwill90/fox ``` -------------------------------- ### Example: Creating an Unmanaged Read-Write Transaction Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md This example demonstrates how to create and use an unmanaged read-write transaction with the fox router. It shows how to handle a route within the transaction, iterate over routes, delete routes, and finally commit the transaction. ```Go f, _ := New() // Txn create an unmanaged read-write or read-only transaction. txn := f.Txn(true) defer txn.Abort() if _, err := txn.Handle(http.MethodGet, "exemple.com/hello/{name}", func(c Context) { _ = c.String(http.StatusOK, "hello %s", c.Param("name")) }); err != nil { log.Printf("error inserting route: %s", err) return } // Iter returns a collection of range iterators for traversing registered routes. it := txn.Iter() // When Iter() is called on a write transaction, it creates a point-in-time snapshot of the transaction state. // It means that writing on the current transaction while iterating is allowed, but the mutation will not be // observed in the result returned by Prefix (or any other iterator). for method, route := range it.Prefix(it.Methods(), "tmp.exemple.com/") { if _, err := f.Delete(method, route.Pattern()); err != nil { log.Printf("error deleting route: %s", err) return } } // Finalize the transaction txn.Commit() ``` -------------------------------- ### Fox Router Prioritization Matching Example Source: https://github.com/tigerwill90/fox/blob/master/README.md This example illustrates the Fox router's prioritization logic, showing how static routes take precedence over named parameters, which in turn are prioritized over catch-all parameters when matching incoming requests. ```text Route Definitions: 1. GET /fs/avengers.txt # Highest priority (static) 2. GET /fs/{filename} # Next priority (named parameter) 3. GET /fs/*{filepath} # Lowest priority (catch-all parameter) Request Matching: - /fs/avengers.txt matches Route 1 - /fs/ironman.txt matches Route 2 - /fs/avengers/ironman.txt matches Route 3 ``` -------------------------------- ### Implement Global Logging Middleware in Fox Go Source: https://github.com/tigerwill90/fox/blob/master/README.md This example illustrates how to create a custom logging middleware and register it globally using the `fox.WithMiddleware` option. The middleware logs route, latency, status, and response size for all requests, including those to 404 and 405 handlers. ```Go package main import ( "github.com/tigerwill90/fox" "log" "net/http" "time" ) func Logger(next fox.HandlerFunc) fox.HandlerFunc { return func(c fox.Context) { start := time.Now() next(c) log.Printf("route: %s, latency: %s, status: %d, size: %d", c.Pattern(), time.Since(start), c.Writer().Status(), c.Writer().Size(), ) } } func main() { f, err := fox.New(fox.WithMiddleware(Logger)) if err != nil { panic(err) } f.MustHandle(http.MethodGet, "/", func(c fox.Context) { resp, err := http.Get("https://api.coindesk.com/v1/bpi/currentprice.json") if err != nil { http.Error(c.Writer(), http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } defer resp.Body.Close() _ = c.Stream(http.StatusOK, fox.MIMEApplicationJSON, resp.Body) }) log.Fatalln(http.ListenAndServe(":8080", f)) } ``` -------------------------------- ### Go Example for Router Reverse Lookup Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Demonstrates how to perform a reverse lookup on the router tree using `Router.Reverse`. It shows how to register a route with a pattern and then use `Reverse` to find that route based on a specific method, host, and path, printing the matched route's pattern. ```go f, _ := New() f.MustHandle(http.MethodGet, "exemple.com/hello/{name}", emptyHandler) route, _ := f.Reverse(http.MethodGet, "exemple.com", "/hello/fox") fmt.Println(route.Pattern()) // /hello/{name} ``` -------------------------------- ### Fox Router Named Parameter Patterns Source: https://github.com/tigerwill90/fox/blob/master/README.md Explains the syntax and behavior of named parameters in Fox routes, using curly braces `{}`. It provides examples of valid and invalid route matches, demonstrating how parameters capture single non-empty route segments. ```APIDOC Pattern /avengers/{name} /avengers/ironman matches /avengers/thor matches /avengers/hulk/angry no matches /avengers/ no matches Pattern /users/uuid:{id} /users/uuid:123 matches /users/uuid: no matches Pattern /users/uuid:{id}/config /users/uuid:123/config matches /users/uuid:/config no matches ``` -------------------------------- ### Fox Router Infix Catch-all Parameter Patterns Source: https://github.com/tigerwill90/fox/blob/master/README.md Explains how infix catch-all parameters function within a route, matching multiple segments before a fixed trailing segment. Examples demonstrate their application in complex path structures where a catch-all is not at the very end. ```APIDOC Pattern: /assets/*{path}/thumbnail /assets/images/thumbnail matches /assets/photos/2021/thumbnail matches /assets/thumbnail no matches Pattern: /assets/path:*{path}/thumbnail /assets/path:images/thumbnail matches /assets/path:photos/2021/thumbnail matches /assets/path:thumbnail no matches ``` -------------------------------- ### Dynamically Register, Update, and Delete Routes in Go with Fox Source: https://github.com/tigerwill90/fox/blob/master/README.md This Go example demonstrates how to dynamically manage HTTP routes (add, update, delete) using the Fox routing library. It sets up a handler for `/routes/{action}` that processes incoming JSON requests to perform the specified routing operation (e.g., `add`, `update`, `delete`) for a given method and path. The design ensures these operations are perfectly safe and may be executed concurrently. ```go package main import ( "encoding/json" "errors" "fmt" "github.com/tigerwill90/fox" "log" "net/http" "strings" ) func Action(c fox.Context) { var data map[string]string if err := json.NewDecoder(c.Request().Body).Decode(&data); err != nil { http.Error(c.Writer(), err.Error(), http.StatusBadRequest) return } method := strings.ToUpper(data["method"]) path := data["path"] text := data["text"] if path == "" || method == "" { http.Error(c.Writer(), "missing method or path", http.StatusBadRequest) return } var err error action := c.Param("action") switch action { case "add": _, err = c.Fox().Handle(method, path, func(c fox.Context) { _ = c.String(http.StatusOK, text) }) case "update": _, err = c.Fox().Update(method, path, func(c fox.Context) { _ = c.String(http.StatusOK, text) }) case "delete": _, err = c.Fox().Delete(method, path) default: http.Error(c.Writer(), fmt.Sprintf("action %q is not allowed", action), http.StatusBadRequest) return } if err != nil { http.Error(c.Writer(), err.Error(), http.StatusConflict) return } _ = c.String(http.StatusOK, "%s route [%s] %s: success\n", action, method, path) } func main() { f, err := fox.New(fox.DefaultOptions()) if err != nil { panic(err) } f.MustHandle(http.MethodPost, "/routes/{action}", Action) if err := http.ListenAndServe(":8080", f); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalln(err) } } ``` -------------------------------- ### Configure Fox Router with Rightmost Non-Private Client IP Resolver Source: https://github.com/tigerwill90/fox/blob/master/README.md This Go example demonstrates how to initialize a Fox router with a `NewRightmostNonPrivate` client IP resolver, which attempts to find the rightmost non-private IP address from the `X-Forwarded-For` header. It shows how to handle the resolved IP address or an error if resolution fails, emphasizing that errors should be treated as application issues. ```go package main import ( "fmt" "github.com/tigerwill90/fox" "github.com/tigerwill90/fox/clientip" "net/http" ) func main() { resolver, err := clientip.NewRightmostNonPrivate(clientip.XForwardedForKey) if err != nil { panic(err) } f, err := fox.New( fox.DefaultOptions(), fox.WithClientIPResolver( resolver, ), ) if err != nil { panic(err) } f.MustHandle(http.MethodGet, "/foo/bar", func(c fox.Context) { ipAddr, err := c.ClientIP() if err != nil { // If the current resolver is not able to derive the client IP, an error // will be returned rather than falling back on an untrustworthy IP. It // should be treated as an application issue or a misconfiguration. panic(err) } fmt.Println(ipAddr.String()) }) } ``` -------------------------------- ### Fox Router Ending Catch-all Parameter Patterns Source: https://github.com/tigerwill90/fox/blob/master/README.md Illustrates the use of ending catch-all parameters, denoted by `*{param}`, which match one or more non-empty route segments including slashes. Examples show how they capture remaining path segments at the end of a route. ```APIDOC Pattern /src/*{filepath} /src/conf.txt matches /src/dir/config.txt matches /src/ no matches Pattern /src/file=*{path} /src/file=config.txt matches /src/file=/dir/config.txt matches /src/file= no matches ``` -------------------------------- ### Attach Per-Route Middleware in Fox Go Source: https://github.com/tigerwill90/fox/blob/master/README.md This example shows how to attach middleware directly to individual routes using `fox.WithMiddleware` as an option to `f.MustHandle`. It's important to note that route-specific middleware must be explicitly reapplied if a route is updated, otherwise, it will revert to using only global middleware. ```Go f, _ := fox.New( f.WithMiddleware(fox.Logger()), ) f.MustHandle("GET", "/", SomeHandler, fox.WithMiddleware(foxtimeout.Middleware(2*time.Second))) f.MustHandle("GET", "/foo", SomeOtherHandler) ``` -------------------------------- ### Perform Unmanaged Read-Write Transactions in Go with Fox Source: https://github.com/tigerwill90/fox/blob/master/README.md This Go example demonstrates an unmanaged read-write transaction using `f.Txn(true)`. It shows how to explicitly handle route operations (insert, delete) within the transaction. The transaction must be explicitly committed with `txn.Commit()` or aborted with `txn.Abort()` (often via `defer`) to finalize its state. Similar to managed transactions, iteration captures a snapshot. ```go // Txn create an unmanaged read-write or read-only transaction. txn := f.Txn(true) defer txn.Abort() if _, err := txn.Handle(http.MethodGet, "exemple.com/hello/{name}", Handler); err != nil { log.Printf("error inserting route: %s", err) return } // Iter returns a collection of range iterators for traversing registered routes. it := txn.Iter() // When Iter() is called on a write transaction, it creates a point-in-time snapshot of the transaction state. // It means that writing on the current transaction while iterating is allowed, but the mutation will not be // observed in the result returned by Prefix (or any other iterator). for method, route := range it.Prefix(it.Methods(), "tmp.exemple.com/") { if _, err := txn.Delete(method, route.Pattern()); err != nil { log.Printf("error deleting route: %s", err) return } } // Finalize the transaction txn.Commit() ``` -------------------------------- ### Allowed Route Definitions in Fox Router Source: https://github.com/tigerwill90/fox/blob/master/README.md This snippet provides examples of valid route definitions in the Fox router, demonstrating how different types of segments (catch-all, named parameters, static) can coexist without conflict, adhering to the router's prioritization rules. ```text GET /*{filepath} GET /users/{id} GET /users/{id}/emails GET /users/{id}/{actions} POST /users/{name}/emails ``` -------------------------------- ### Get Point-in-Time Transaction Snapshot with Txn.Snapshot (Go) Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Returns a point-in-time snapshot of the current transaction state. It provides a new read-only transaction or `nil` if the transaction is already aborted or committed. ```Go func (txn *Txn) Snapshot() *Txn ``` -------------------------------- ### Chain Multiple Client IP Resolvers in Fox Router Source: https://github.com/tigerwill90/fox/blob/master/README.md This Go example illustrates how to create a chain of client IP resolvers using `clientip.NewChain`. It combines `NewLeftmostNonPrivate` (from `ForwardedKey`) and `NewRemoteAddr` to provide a robust fallback mechanism for client IP resolution, which is particularly useful in mixed network environments where a server might be directly connected to the internet and also expect a header to check. ```go resolver, _ := clientip.NewLeftmostNonPrivate(clientip.ForwardedKey, 10) f, _ = fox.New( fox.DefaultOptions(), fox.WithClientIPResolver( // A common use for this is if a server is both directly connected to the // internet and expecting a header to check. clientip.NewChain( resolver, clientip.NewRemoteAddr(), ), ), ) ``` -------------------------------- ### WithClientIPResolver Option Function Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md WithClientIPResolver sets the resolver for obtaining the "real" client IP address from HTTP requests. This resolver is used by the Context.ClientIP method. The resolver must be chosen and tuned for your network configuration to ensure it never returns an error -- i.e., never fails to find a candidate for the "real" IP. Consequently, getting an error result should be treated as an application error, perhaps even worthy of panicking. There is no sane default, so if no resolver is configured, Context.ClientIP returns ErrNoClientIPResolver. This option can be applied on a per-route basis or globally: If applied globally, it affects all routes by default. If applied to a specific route, it will override the global setting for that route. Setting the resolver to nil is equivalent to no resolver configured. ```Go func WithClientIPResolver(resolver ClientIPResolver) Option ``` -------------------------------- ### Get Go Fox Route Parameter by Name Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md The `Get` method on the `Params` type retrieves the value of a specific wildcard segment by its name. It returns an empty string if no matching parameter is found. ```Go func (p Params) Get(name string) string ``` -------------------------------- ### Get Number of Registered Routes in Go Transaction Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Returns the total number of routes currently registered within the transaction. ```Go func (txn *Txn) Len() int ``` ```APIDOC Txn.Len(): int Purpose: Returns the number of registered routes. Parameters: None Returns: int: The total number of registered routes. ``` -------------------------------- ### Get Number of Registered Routes in Go fox Router Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Returns the total number of registered routes currently in the router. ```Go func (fox *Router) Len() int ``` ```APIDOC Router.Len() -> int Returns: The number of registered routes. ``` -------------------------------- ### Go Function to Set Up Signal Handler Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md The `SetupHandler` function registers handlers for `SIGTERM` and `SIGINT` signals. It returns a `context.Context` that is cancelled when one of these signals is received, facilitating graceful shutdown. If a second signal is caught, the program terminates immediately with exit code 1. ```go func SetupHandler() context.Context ``` -------------------------------- ### Create New TestContext (Go) Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Returns a new `Context` instance specifically designed for testing purposes. It requires an `http.ResponseWriter`, an `*http.Request`, and accepts optional `GlobalOption`s. ```Go func NewTestContextOnly(w http.ResponseWriter, r *http.Request, opts ...GlobalOption) *TestContext ``` -------------------------------- ### Import clientip Package for IP Handling (Go) Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Imports the `clientip` package from `github.com/tigerwill90/fox/clientip`. This package provides utilities for handling client IP addresses within the `fox` routing framework. ```Go import "github.com/tigerwill90/fox/clientip" ``` -------------------------------- ### Importing the fox Go Package Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md This snippet shows the standard Go import path for the 'fox' package, allowing its functions and types to be used in a Go project. ```Go import "github.com/tigerwill90/fox" ``` -------------------------------- ### Go ClientIPResolverFunc Type and Adapter Method Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Describes `ClientIPResolverFunc`, an adapter type that allows ordinary functions to be used as `ClientIPResolver` implementations. If `f` is a function with the appropriate signature, `ClientIPResolverFunc(f)` is a `ClientIPResolverFunc` that calls `f`. It also details the `ClientIP` method for this adapter, which simply calls the underlying function `f(c)`. ```Go type ClientIPResolverFunc func(c Context) (*net.IPAddr, error) ``` ```Go func (f ClientIPResolverFunc) ClientIP(c Context) (*net.IPAddr, error) ``` ```APIDOC Type: ClientIPResolverFunc Description: An adapter to allow the use of ordinary functions as ClientIPResolver. Signature: func(c Context) (*net.IPAddr, error) Method: ClientIPResolverFunc.ClientIP Description: Calls the underlying function `f(c)`. Signature: func (f ClientIPResolverFunc) ClientIP(c Context) (*net.IPAddr, error) Parameters: c: Context Returns: *net.IPAddr, error ``` -------------------------------- ### Go HTTP Router Parameter Write Benchmarks Source: https://github.com/tigerwill90/fox/blob/master/README.md Micro-benchmarks comparing the performance of different Go HTTP routers when writing parameters, highlighting Fox's efficiency in minimizing heap allocations. The results show `Fox` and `Traffic` routers' performance in nanoseconds per operation, bytes allocated per operation, and total allocations per operation. ```Go BenchmarkMartini_ParamWrite 454255 2667 ns/op 1168 B/op 16 allocs/op BenchmarkTraffic_ParamWrite 511766 2021 ns/op 2272 B/op 25 allocs/op ``` -------------------------------- ### Fox RouteOption API Reference Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md API documentation for the `RouteOption` interface, used for configuring routes, and the `WithAnnotation` function to attach metadata. ```APIDOC type RouteOption interface { // contains filtered or unexported methods } func WithAnnotation(key, value any) RouteOption Description: Attach arbitrary metadata to routes. Annotations are key-value pairs that allow middleware, handler or any other components to modify behavior based on the attached metadata. Parameters: key: The annotation key (must be comparable and not string or any other built-in type). value: The annotation value. Returns: RouteOption ``` -------------------------------- ### Go Router Static Route Performance Benchmarks (GOMAXPROCS: 1) Source: https://github.com/tigerwill90/fox/blob/master/README.md This benchmark compares the performance of several Go HTTP routers (HttpRouter, HttpTreeMux, Fox, StdMux, Gin, Echo, Beego, GorillaMux, Martini, Traffic, Pat) when handling static routes with a single CPU core. It shows the operations per second, time per operation, memory allocation, and number of allocations for each router, indicating their relative efficiency. ```Go BenchmarkHttpRouter_StaticAll 161659 7570 ns/op 0 B/op 0 allocs/op BenchmarkHttpTreeMux_StaticAll 132446 8836 ns/op 0 B/op 0 allocs/op BenchmarkFox_StaticAll 102577 11348 ns/op 0 B/op 0 allocs/op BenchmarkStdMux_StaticAll 91304 13382 ns/op 0 B/op 0 allocs/op BenchmarkGin_StaticAll 78224 15433 ns/op 0 B/op 0 allocs/op BenchmarkEcho_StaticAll 77923 15739 ns/op 0 B/op 0 allocs/op BenchmarkBeego_StaticAll 10000 101094 ns/op 55264 B/op 471 allocs/op BenchmarkGorillaMux_StaticAll 2283 525683 ns/op 113041 B/op 1099 allocs/op BenchmarkMartini_StaticAll 1330 936928 ns/op 129210 B/op 2031 allocs/op BenchmarkTraffic_StaticAll 1064 1140959 ns/op 753611 B/op 14601 allocs/op BenchmarkPat_StaticAll 967 1230424 ns/op 602832 B/op 12559 allocs/op ``` -------------------------------- ### Get Route Iterators in Go fox Router Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Returns a collection of range iterators for traversing registered methods and routes. It creates a point-in-time snapshot of the routing tree, meaning all iterators returned will not observe subsequent writes on the router. This function is safe for concurrent use by multiple goroutines and while mutations on routes are ongoing. ```Go func (fox *Router) Iter() Iter ``` ```APIDOC Router.Iter() -> Iter Returns: A collection of range iterators (`Iter`) for traversing registered methods and routes. ``` -------------------------------- ### Wrap http.Handler with Fox Adapters in Go Source: https://github.com/tigerwill90/fox/blob/master/README.md This snippet demonstrates how to wrap an existing `http.Handler` or `http.HandlerFunc` using Fox's `fox.WrapH` adapter. It shows how to access route parameters from the `context.Context` within the wrapped handler using `fox.ParamsFromContext`. ```Go articles := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { params := fox.ParamsFromContext(r.Context()) _, _ = fmt.Fprintf(w, "Article id: %s\n", params.Get("id")) }) f, _ := fox.New(fox.DefaultOptions()) f.MustHandle(http.MethodGet, "/articles/{id}", fox.WrapH(httpRateLimiter.RateLimit(articles))) ``` -------------------------------- ### Configure Trailing Slash Redirection in Go Fox Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md The `WithRedirectTrailingSlash` option enables automatic redirection for requests that don't match a route but would match with an additional or removed trailing slash. It performs a 301 redirect for GET requests and 308 for others. This option can be applied globally or per-route, overriding global settings. It is mutually exclusive with `WithIgnoreTrailingSlash`. ```Go func WithRedirectTrailingSlash(enable bool) Option ``` -------------------------------- ### Router.ServeHTTP Method Definition Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Defines the `ServeHTTP` method, which serves as the main entry point for handling incoming HTTP requests. It dispatches requests to the appropriate handler function based on the request's method and path, implementing the `http.Handler` interface. ```Go func (fox *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) ``` -------------------------------- ### Go Custom Middleware for Path Cleaning and Redirection Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Demonstrates creating a custom middleware that cleans the request path, performs a manual route lookup using `Router.Lookup`, and redirects the client to the valid path if a match is found. It handles trailing slashes and different HTTP methods for redirection, ensuring the original path is restored if no redirection occurs. ```go redirectFixedPath := MiddlewareFunc(func(next HandlerFunc) HandlerFunc { return func(c Context) { req := c.Request() target := req.URL.Path cleanedPath := CleanPath(target) // Nothing to clean, call next handler. if cleanedPath == target { next(c) return } req.URL.Path = cleanedPath route, cc, tsr := c.Fox().Lookup(c.Writer(), req) if route != nil { defer cc.Close() code := http.StatusMovedPermanently if req.Method != http.MethodGet { code = http.StatusPermanentRedirect } // Redirect the client if direct match or indirect match. if !tsr || route.IgnoreTrailingSlashEnabled() { if err := c.Redirect(code, cleanedPath); err != nil { // Only if not in the range 300..308, so not possible here! panic(err) } return } // Add or remove an extra trailing slash and redirect the client. if route.RedirectTrailingSlashEnabled() { if err := c.Redirect(code, FixTrailingSlash(cleanedPath)); err != nil { // Only if not in the range 300..308, so not possible here panic(err) } return } } // rollback to the original path before calling the // next handler or middleware. req.URL.Path = target next(c) } }) f, _ := New( // Register the middleware for the NoRouteHandler scope. WithMiddlewareFor(NoRouteHandler|NoMethodHandler, redirectFixedPath), ) f.MustHandle(http.MethodGet, "/hello/{name}", func(c Context) { _ = c.String(200, "Hello %s\n", c.Param("name")) }) ``` -------------------------------- ### Go Router Performance: Multiple Parameters Route Benchmarks Source: https://github.com/tigerwill90/fox/blob/master/README.md Performance benchmarks for Go router implementations, evaluating their scalability when handling routes with multiple parameters (5 and 20). The results illustrate how different routers' performance metrics, such as operations per second and memory allocations, are affected by an increasing number of route parameters, with GOMAXPROCS set to 1. ```Go BenchmarkFox_Param5 16608495 72.84 ns/op 0 B/op 0 allocs/op BenchmarkGin_Param5 13098740 92.22 ns/op 0 B/op 0 allocs/op BenchmarkEcho_Param5 12025460 96.33 ns/op 0 B/op 0 allocs/op BenchmarkHttpRouter_Param5 8233530 148.1 ns/op 160 B/op 1 allocs/op BenchmarkHttpTreeMux_Param5 1986019 616.9 ns/op 576 B/op 6 allocs/op BenchmarkBeego_Param5 1836229 655.3 ns/op 352 B/op 3 allocs/op BenchmarkGorillaMux_Param5 757936 1572 ns/op 1088 B/op 8 allocs/op BenchmarkPat_Param5 645847 1724 ns/op 800 B/op 24 allocs/op BenchmarkTraffic_Param5 424431 2729 ns/op 2200 B/op 27 allocs/op BenchmarkMartini_Param5 424806 2772 ns/op 1256 B/op 13 allocs/op BenchmarkGin_Param20 4636416 244.6 ns/op 0 B/op 0 allocs/op BenchmarkFox_Param20 4667533 250.7 ns/op 0 B/op 0 allocs/op BenchmarkEcho_Param20 4352486 277.1 ns/op 0 B/op 0 allocs/op BenchmarkHttpRouter_Param20 2618958 455.2 ns/op 640 B/op 1 allocs/op BenchmarkBeego_Param20 847029 1688 ns/op 352 B/op 3 allocs/op BenchmarkHttpTreeMux_Param20 369500 2972 ns/op 3195 B/op 10 allocs/op BenchmarkGorillaMux_Param20 318134 3561 ns/op 3195 B/op 10 allocs/op BenchmarkMartini_Param20 223070 5117 ns/op 3619 B/op 15 allocs/op BenchmarkPat_Param20 157380 7442 ns/op 4094 B/op 73 allocs/op BenchmarkTraffic_Param20 119677 9864 ns/op 7847 B/op 47 allocs/op ``` -------------------------------- ### Go Route.Handle Method Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Invokes the route's handler with the provided `Context`. For middleware application, refer to `Route.HandleMiddleware`. ```Go func (r *Route) Handle(c Context) ``` ```APIDOC Route.Handle(c Context): Description: Calls the handler with the provided Context. Parameters: c: Context - The context for the request. See Also: Route.HandleMiddleware ``` -------------------------------- ### Cloning Fox Context for Asynchronous Go Routines Source: https://github.com/tigerwill90/fox/blob/master/README.md This Go snippet demonstrates how to properly handle `fox.Context` when performing asynchronous operations. By cloning the context using `c.Clone()`, you ensure that the context's resources are not prematurely freed, allowing safe access to parameters within a goroutine. ```go func Hello(c fox.Context) { cc := c.Clone() go func() { time.Sleep(2 * time.Second) log.Println(cc.Param("name")) // Safe }() _ = c.String(http.StatusOK, "Hello %s\n", c.Param("name")) } ``` -------------------------------- ### Go Signals Package Import Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md This snippet demonstrates the import statement for the `signals` package from `github.com/tigerwill90/fox/signals`. This package provides utilities for handling system signals like `SIGTERM` and `SIGINT` for graceful application shutdown. ```go import "github.com/tigerwill90/fox/signals" ``` -------------------------------- ### Fox Router Named Parameters in Hostnames Source: https://github.com/tigerwill90/fox/blob/master/README.md Demonstrates how named parameters can be used within hostname patterns in Fox routes. It clarifies that the path portion of the route must still include at least a `/` even when hostnames contain parameters. ```APIDOC Pattern example.com/avengers example.com/avengers matches {sub}.com/avengers matches example.{tld}/avengers matches {sub}.example.com/avengers no matches ``` -------------------------------- ### Go Router Concurrent Static Route Performance Benchmarks (GOMAXPROCS: 16) Source: https://github.com/tigerwill90/fox/blob/master/README.md This benchmark specifically compares the Fox router and HttpTreeMux's performance for static routes under high concurrency (16 CPU cores). It highlights Fox's superior efficiency in parallel scenarios and demonstrates the overhead incurred by HttpTreeMux's use of higher synchronization primitives like RWMutex when routes are added concurrently. ```Go Route: all BenchmarkFox_StaticAll-16 99322 11369 ns/op 0 B/op 0 allocs/op BenchmarkFox_StaticAllParallel-16 831354 1422 ns/op 0 B/op 0 allocs/op BenchmarkHttpTreeMux_StaticAll-16 135560 8861 ns/op 0 B/op 0 allocs/op BenchmarkHttpTreeMux_StaticAllParallel-16* 172714 6916 ns/op 0 B/op 0 allocs/op ``` -------------------------------- ### Go HTTP Router GitHub API Route Benchmarks Source: https://github.com/tigerwill90/fox/blob/master/README.md Benchmarks comparing various Go HTTP routers' performance when handling 203 GitHub API routes with GOMAXPROCS: 1. The results demonstrate Fox's superior speed and zero allocations across a large number of routes compared to other popular Go routers like Echo, Gin, and HttpRouter. ```Go BenchmarkFox_GithubAll 63984 18555 ns/op 0 B/op 0 allocs/op BenchmarkEcho_GithubAll 49312 23353 ns/op 0 B/op 0 allocs/op BenchmarkGin_GithubAll 48422 24926 ns/op 0 B/op 0 allocs/op BenchmarkHttpRouter_GithubAll 45706 26818 ns/op 14240 B/op 171 allocs/op BenchmarkHttpTreeMux_GithubAll 14731 80133 ns/op 67648 B/op 691 allocs/op BenchmarkBeego_GithubAll 7692 137926 ns/op 72929 B/op 625 allocs/op BenchmarkTraffic_GithubAll 636 1916586 ns/op 845114 B/op 14634 allocs/op BenchmarkMartini_GithubAll 530 2205947 ns/op 238546 B/op 2813 allocs/op BenchmarkGorillaMux_GithubAll 529 2246380 ns/op 203844 B/op 1620 allocs/op BenchmarkPat_GithubAll 424 2899405 ns/op 1843501 B/op 29064 allocs/op ``` -------------------------------- ### Go Router Performance: Single Parameter Route Benchmarks Source: https://github.com/tigerwill90/fox/blob/master/README.md Benchmarks comparing various Go router implementations for handling a single route with one parameter. Results show operations per second, time per operation, memory allocation, and number of allocations, providing insights into their basic performance overhead when GOMAXPROCS is set to 1. ```Go BenchmarkFox_Param 33024534 36.61 ns/op 0 B/op 0 allocs/op BenchmarkEcho_Param 31472508 38.71 ns/op 0 B/op 0 allocs/op BenchmarkGin_Param 25826832 52.88 ns/op 0 B/op 0 allocs/op BenchmarkHttpRouter_Param 21230490 60.83 ns/op 32 B/op 1 allocs/op BenchmarkHttpTreeMux_Param 3960292 280.4 ns/op 352 B/op 3 allocs/op BenchmarkBeego_Param 2247776 518.9 ns/op 352 B/op 3 allocs/op BenchmarkPat_Param 1603902 676.6 ns/op 512 B/op 10 allocs/op BenchmarkGorillaMux_Param 1000000 1011 ns/op 1024 B/op 8 allocs/op BenchmarkTraffic_Param 648986 1686 ns/op 1848 B/op 21 allocs/op BenchmarkMartini_Param 485839 2446 ns/op 1096 B/op 12 allocs/op ``` -------------------------------- ### Go Route.HandleMiddleware Method Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Invokes the route's handler with route-specific middleware applied, using the provided `Context`. ```Go func (r *Route) HandleMiddleware(c Context, _ ...struct{}) ``` ```APIDOC Route.HandleMiddleware(c Context, _ ...struct{}): Description: Calls the handler with route-specific middleware applied, using the provided Context. Parameters: c: Context - The context for the request. ``` -------------------------------- ### Router.ServeHTTP Method Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Implements the http.Handler interface, allowing the router to serve HTTP requests. It dispatches incoming requests to the appropriate handlers. ```APIDOC func (fox *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) ``` -------------------------------- ### Go: NewSingleIPHeader Constructor Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md The `NewSingleIPHeader` function creates a `SingleIPHeader` resolver. It takes `headerName` as a parameter, which specifies the request header to use for obtaining the client IP. ```go func NewSingleIPHeader(headerName string) (SingleIPHeader, error) ``` ```APIDOC NewSingleIPHeader: Signature: func NewSingleIPHeader(headerName string) (SingleIPHeader, error) Description: Creates a SingleIPHeader resolver. Parameters: headerName: string - The request header to use for getting the client IP. Returns: SingleIPHeader: The created resolver. error: An error if creation fails. ``` -------------------------------- ### Configure Automatic OPTIONS and CORS Handling in Fox Go Source: https://github.com/tigerwill90/fox/blob/master/README.md This snippet demonstrates how to customize the automatic handling of OPTIONS requests, which are commonly used as preflight requests for CORS. By registering a custom handler with `fox.WithOptionsHandler`, you can set appropriate CORS headers like `Access-Control-Allow-Methods` and `Access-Control-Allow-Origin`. ```Go f, _ := fox.New( fox.WithOptionsHandler(func(c fox.Context) { if c.Header("Access-Control-Request-Method") != "" { // Setting CORS headers. c.SetHeader("Access-Control-Allow-Methods", c.Writer().Header().Get("Allow")) c.SetHeader("Access-Control-Allow-Origin", "*") } // Respond with a 204 status code. c.Writer().WriteHeader(http.StatusNoContent) }), ) ``` -------------------------------- ### Go Function NewTestContext Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Creates a new `Router` and its associated `Context`, specifically designed for testing purposes. This function facilitates isolated testing of router behavior. ```Go func NewTestContext(w http.ResponseWriter, r *http.Request, opts ...GlobalOption) (*Router, *TestContext) ``` -------------------------------- ### Go WithMiddlewareFor Function Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Attaches one or more middleware functions to the router for a specified `HandlerScope`. This provides fine-grained control over which types of handlers (e.g., `RouteHandler`, `NoRouteHandler`) the middleware will apply to, with middlewares chained in the order they are provided. ```Go func WithMiddlewareFor(scope HandlerScope, m ...MiddlewareFunc) GlobalOption ``` -------------------------------- ### Go ResponseWriter Interface Definition Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Defines the `ResponseWriter` interface, extending standard `http.ResponseWriter` with additional methods for status, written state, size, flushing, hijacking, HTTP/2 push, and setting read/write deadlines, along with full duplex support for concurrent request body reads and response writes. ```Go type ResponseWriter interface { http.ResponseWriter io.StringWriter io.ReaderFrom // Status recorded after Write and WriteHeader. Status() int // Written returns true if the response has been written. Written() bool // Size returns the size of the written response. Size() int // FlushError flushes buffered data to the client. If flush is not supported, FlushError returns an error // matching [http.ErrNotSupported]. See [http.Flusher] for more details. FlushError() error // Hijack lets the caller take over the connection. If hijacking the connection is not supported, Hijack returns // an error matching [http.ErrNotSupported]. See [http.Hijacker] for more details. Hijack() (net.Conn, *bufio.ReadWriter, error) // Push initiates an HTTP/2 server push. Push returns [http.ErrNotSupported] if the client has disabled push or if push // is not supported on the underlying connection. See [http.Pusher] for more details. Push(target string, opts *http.PushOptions) error // SetReadDeadline sets the deadline for reading the entire request, including the body. Reads from the request // body after the deadline has been exceeded will return an error. A zero value means no deadline. Setting the read // deadline after it has been exceeded will not extend it. If SetReadDeadline is not supported, it returns // an error matching [http.ErrNotSupported]. SetReadDeadline(deadline time.Time) error // SetWriteDeadline sets the deadline for writing the response. Writes to the response body after the deadline has // been exceeded will not block, but may succeed if the data has been buffered. A zero value means no deadline. // Setting the write deadline after it has been exceeded will not extend it. If SetWriteDeadline is not supported, // it returns an error matching [http.ErrNotSupported]. SetWriteDeadline(deadline time.Time) error // EnableFullDuplex indicates that the request handler will interleave reads from [http.Request.Body] // with writes to the [ResponseWriter]. // // For HTTP/1 requests, the Go HTTP server by default consumes any unread portion of // the request body before beginning to write the response, preventing handlers from // concurrently reading from the request and writing the response. // Calling EnableFullDuplex disables this behavior and permits handlers to continue to read // from the request while concurrently writing the response. // // For HTTP/2 requests, the Go HTTP server always permits concurrent reads and responses. // If EnableFullDuplex is not supported, it returns an error matching [http.ErrNotSupported]. EnableFullDuplex() error } ``` ```APIDOC ResponseWriter interface: Extends: - http.ResponseWriter - io.StringWriter - io.ReaderFrom Methods: Status() int: Description: Returns the status code recorded after Write and WriteHeader. Written() bool: Description: Returns true if the response has been written. Size() int: Description: Returns the size of the written response. FlushError() error: Description: Flushes buffered data to the client. Returns http.ErrNotSupported if flush is not supported. See Also: http.Flusher Hijack() (net.Conn, *bufio.ReadWriter, error): Description: Lets the caller take over the connection. Returns http.ErrNotSupported if hijacking is not supported. See Also: http.Hijacker Push(target string, opts *http.PushOptions) error: Description: Initiates an HTTP/2 server push. Returns http.ErrNotSupported if client disabled push or not supported. Parameters: target: string opts: *http.PushOptions See Also: http.Pusher SetReadDeadline(deadline time.Time) error: Description: Sets the deadline for reading the entire request, including the body. Returns http.ErrNotSupported if not supported. Parameters: deadline: time.Time SetWriteDeadline(deadline time.Time) error: Description: Sets the deadline for writing the response. Returns http.ErrNotSupported if not supported. Parameters: deadline: time.Time EnableFullDuplex() error: Description: Indicates the request handler will interleave reads from http.Request.Body with writes to the ResponseWriter. Returns http.ErrNotSupported if not supported. Notes: - For HTTP/1, disables default behavior of consuming unread body before writing response. - For HTTP/2, concurrent reads and responses are always permitted. ``` -------------------------------- ### Go Type: Router and Constructor Method Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Defines the Go type Router and its constructor method for creating new router instances. ```APIDOC type Router func New(opts ...GlobalOption) (*Router, error) ``` -------------------------------- ### Initialize RightmostTrustedCount Resolver in Go Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md This function creates a new `RightmostTrustedCount` resolver. It requires a `HeaderKey` and `trustedCount`, which specifies the number of trusted reverse proxies. The returned IP will be the `(trustedCount-1)`th from the right, effectively identifying the IP from the first untrusted source. ```Go func NewRightmostTrustedCount(key HeaderKey, trustedCount uint) (RightmostTrustedCount, error) ``` -------------------------------- ### Go Function SplitHostPath Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Separates the host and path components from a URL string. It handles port stripping if a valid numeric port is present and defaults the path to '/' if empty or missing. Host validation is not performed. ```Go func SplitHostPath(url string) (host, path string) ``` -------------------------------- ### Go Type: GlobalOption and Configuration Methods Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Defines the Go type GlobalOption and its associated methods for configuring global router behavior. ```APIDOC type GlobalOption func DefaultOptions() GlobalOption func WithAutoOptions(enable bool) GlobalOption func WithMaxRouteParamKeyBytes(max uint16) GlobalOption func WithMaxRouteParams(max uint16) GlobalOption func WithMiddlewareFor(scope HandlerScope, m ...MiddlewareFunc) GlobalOption func WithNoMethod(enable bool) GlobalOption func WithNoMethodHandler(handler HandlerFunc) GlobalOption func WithNoRouteHandler(handler HandlerFunc) GlobalOption func WithOptionsHandler(handler HandlerFunc) GlobalOption ``` -------------------------------- ### Go Type: Param Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Defines the Go type Param, representing a single route parameter. ```APIDOC type Param ``` -------------------------------- ### Go Route.ClientIPResolver Method Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Returns the `ClientIPResolver` configured for the route, if any. ```Go func (r *Route) ClientIPResolver() ClientIPResolver ``` ```APIDOC Route.ClientIPResolver() ClientIPResolver: Description: Returns the ClientIPResolver configured for the route, if any. Returns: ClientIPResolver - The configured client IP resolver. ``` -------------------------------- ### Wrap Standard http.HandlerFunc into Fox HandlerFunc Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Adapts a standard `http.HandlerFunc` into a `fox.HandlerFunc`. This utility allows existing `http.HandlerFunc` implementations to be used within the 'fox' routing context, enabling access to route parameters through the provided context. ```APIDOC func WrapF(f http.HandlerFunc) HandlerFunc ``` -------------------------------- ### Go: NewRightmostTrustedRange Constructor Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md The `NewRightmostTrustedRange` function creates a `RightmostTrustedRange` resolver. It requires a `HeaderKey` (either "X-Forwarded-For" or "Forwarded") and a `TrustedIPRange` implementation containing all trusted reverse proxies on the path to the server. This includes private/internal or external proxies. ```go func NewRightmostTrustedRange(key HeaderKey, resolver TrustedIPRange) (RightmostTrustedRange, error) ``` ```APIDOC NewRightmostTrustedRange: Signature: func NewRightmostTrustedRange(key HeaderKey, resolver TrustedIPRange) (RightmostTrustedRange, error) Description: Creates a RightmostTrustedRange resolver. Parameters: key: HeaderKey - Must be "X-Forwarded-For" or "Forwarded". resolver: TrustedIPRange - Contains all trusted reverse proxies on the path to this server (private/internal or external). Returns: RightmostTrustedRange: The created resolver. error: An error if creation fails. ``` -------------------------------- ### Initialize RightmostNonPrivate Resolver in Go Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md This function creates a new `RightmostNonPrivate` resolver instance. It allows specifying the header key to inspect and optional trusted IP ranges. By default, it trusts loopback, link-local, and private network IP ranges. ```Go func NewRightmostNonPrivate(key HeaderKey, opts ...TrustedRangeOption) (RightmostNonPrivate, error) ``` -------------------------------- ### Overview of fox IP Resolution API Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md This section provides an index of the functions and types available in the `fox` project for client IP resolution and network utility operations, outlining the structure of the API. ```APIDOC Variables: ErrInvalidIpAddress ErrUnspecifiedIpAddress ErrRemoteAddress ErrSingleIPHeader ErrLeftmostNonPrivate ErrRightmostNonPrivate ErrRightmostTrustedCount ErrRightmostTrustedRange Functions: AddressesAndRangesToIPNets(ranges ...string) ([]net.IPNet, error) ParseIPAddr(ip string) (*net.IPAddr, error) Types: BlacklistRangeOption: Methods: ExcludeLinkLocal(enable bool) BlacklistRangeOption ExcludeLoopback(enable bool) BlacklistRangeOption ExcludePrivateNet(enable bool) BlacklistRangeOption Chain: Methods: NewChain(resolvers ...fox.ClientIPResolver) Chain (s Chain) ClientIP(c fox.Context) (*net.IPAddr, error) HeaderKey: Methods: (h HeaderKey) String() string LeftmostNonPrivate: Methods: NewLeftmostNonPrivate(key HeaderKey, limit uint, opts ...BlacklistRangeOption) (LeftmostNonPrivate, error) (s LeftmostNonPrivate) ClientIP(c fox.Context) (*net.IPAddr, error) RemoteAddr: Methods: NewRemoteAddr() RemoteAddr (s RemoteAddr) ClientIP(c fox.Context) (*net.IPAddr, error) RightmostNonPrivate: Methods: NewRightmostNonPrivate(key HeaderKey, opts ...TrustedRangeOption) (RightmostNonPrivate, error) (s RightmostNonPrivate) ClientIP(c fox.Context) (*net.IPAddr, error) RightmostTrustedCount: Methods: NewRightmostTrustedCount(key HeaderKey, trustedCount uint) (RightmostTrustedCount, error) (s RightmostTrustedCount) ClientIP(c fox.Context) (*net.IPAddr, error) RightmostTrustedRange: Methods: NewRightmostTrustedRange(key HeaderKey, resolver TrustedIPRange) (RightmostTrustedRange, error) (s RightmostTrustedRange) ClientIP(c fox.Context) (*net.IPAddr, error) SingleIPHeader: Methods: NewSingleIPHeader(headerName string) (SingleIPHeader, error) (s SingleIPHeader) ClientIP(c fox.Context) (*net.IPAddr, error) TrustedIPRange TrustedIPRangeFunc: Methods: (f TrustedIPRangeFunc) TrustedIPRange() ([]net.IPNet, error) TrustedRangeOption: Methods: TrustLinkLocal(enable bool) TrustedRangeOption TrustLoopback(enable bool) TrustedRangeOption TrustPrivateNet(enable bool) TrustedRangeOption ``` -------------------------------- ### Go Function: NewTestContext Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Defines the Go function NewTestContext, for creating a new test context with a router and HTTP request/response writer. ```APIDOC func NewTestContext(w http.ResponseWriter, r *http.Request, opts ...GlobalOption) (*Router, *TestContext) ``` -------------------------------- ### Go Type: MiddlewareFunc and Middleware Creation Methods Source: https://github.com/tigerwill90/fox/blob/master/docs/api.md Defines the Go type MiddlewareFunc and its associated methods for creating common middleware. ```APIDOC type MiddlewareFunc func CustomRecovery(handle RecoveryFunc) MiddlewareFunc func CustomRecoveryWithLogHandler(handler slog.Handler, handle RecoveryFunc) MiddlewareFunc func Logger() MiddlewareFunc func LoggerWithHandler(handler slog.Handler) MiddlewareFunc func Recovery() MiddlewareFunc ```