Fox
A high-performance Go HTTP router for building reverse proxies and API gateways, including use cases like ingress controllers
Install / Use
/learn @fox-toolkit/FoxREADME
Fox
<img align="right" width="159px" src="https://raw.githubusercontent.com/fox-toolkit/fox/refs/heads/static/fox_logo.png">[!NOTE] This repository has been transferred from
github.com/tigerwill90/foxtogithub.com/fox-toolkit/fox. Existing users should update their imports andgo.modaccordingly.
Fox is a lightweight and high performance HTTP request router for Go, designed for building reverse proxies, API gateways, or other applications that require managing routes at runtime based on configuration changes or external events. It is also well-suited for general use cases such as microservices and REST APIs, though it focuses on routing and does not include convenience helpers found in full-featured frameworks, such as automatic binding, content negotiation, file uploads, cookies, etc.
Fox supports mutation on its routing tree while handling requests concurrently. Internally, it uses a Radix Tree that supports lock-free reads while allowing a concurrent writer, and is optimized for high-concurrency reads and low-concurrency writes. The router supports complex routing patterns, enforces clear priority rules, and performs strict validation to prevent misconfigurations.
Disclaimer
The current API is not yet stabilized. Breaking changes may occur before v1.0.0 and will be noted on the release note.
Features
Runtime updates: Register, update and delete route handler safely at any time without impact on performance.
Flexible routing: Fox strikes a balance between routing flexibility, performance and clarity by enforcing clear priority rules, ensuring that there are no unintended matches and maintaining high performance even for complex routing patterns. Supported features include named parameters, suffix and infix catch-all, regexp constraints, hostname matching, method and method-less routes, route matchers, and sub-routers.
Trailing slash handling: Automatically handle trailing slash inconsistencies by either ignoring them, redirecting to the canonical path, or enforcing strict matching based on your needs.
Path correction: Automatically handle malformed paths with extra slashes or dots by either serving the cleaned path directly or redirecting to the canonical form.
Automatic OPTIONS replies: Fox has built-in native support for OPTIONS requests.
Client IP Derivation: Accurately determine the "real" client IP address using best practices tailored to your network topology.
Growing middleware ecosystem: Fox's middleware ecosystem is still limited, but standard http.Handler middleware are fully compatible. Contributions are welcome!
- Getting started
- Concurrency
- Middleware
- Working with http.Handler
- Handling OPTIONS Requests and CORS Automatically
- Resolving Client IP
- Benchmark
- Road to v1
- Contributions
- License
Getting started
Install
With a correctly configured Go toolchain:
go get -u github.com/fox-toolkit/fox
Basic example
package main
import (
"errors"
"fmt"
"log"
"net/http"
"github.com/fox-toolkit/fox"
)
func HelloServer(c *fox.Context) {
_ = c.String(http.StatusOK, fmt.Sprintf("Hello %s\n", c.Param("name")))
}
func main() {
f := fox.MustRouter(fox.DefaultOptions())
f.MustAdd([]string{http.MethodHead, http.MethodGet}, "/hello/{name}", HelloServer)
if err := http.ListenAndServe(":8080", f); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatalln(err)
}
}
Named parameters
Routes can include named parameters using curly braces {name} to match exactly one non-empty route segment. The matching
segments are recorded as Param and accessible via the
Context. Named parameters are supported anywhere in
the route, but only one parameter is allowed per segment (or hostname label) and must appear at the end of the segment.
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
Pattern {sub}.example.com/avengers
first.example.com/avengers matches
example.com/avengers no matches
Named parameters can include regular expression using the syntax {name:regexp}. Regular expressions cannot
contain capturing groups, but can use non-capturing groups (?:pattern) instead. Regexp support is opt-in via
fox.AllowRegexpParam(true) option.
Pattern /products/{name:[A-Za-z]+}
/products/laptop matches
/products/123 no matches
Named Wildcards (Catch-all)
Named wildcard start with a plus sign + followed by a name {param} and match any sequence of characters
including slashes, but cannot match an empty string. The matching segments are also accessible via
Context. Catch-all parameters are supported anywhere in the route,
but only one parameter is allowed per segment (or hostname label) and must appear at the end of the segment.
Consecutive catch-all parameter are not allowed.
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
Pattern: /assets/+{path}/thumbnail
/assets/images/thumbnail matches
/assets/photos/2021/thumbnail matches
/assets//thumbnail no matches
Pattern +{sub}.example.com/avengers
first.example.com/avengers matches
first.second.example.com/avengers matches
example.com/avengers no matches
Optional named wildcard start with an asterisk * followed by a name {param} and match any sequence of characters
including empty strings. Unlike +{param}, optional wildcards can only be used as a suffix.
Pattern /src/*{filepath}
/src/conf.txt matches
/src/dir/config.txt matches
/src/ matches
Pattern /src/file=*{path}
/src/file=config.txt matches
/src/file=/dir/config.txt matches
/src/file= matches
Named wildcards can include a regular expression constraint using the syntax +{name:regexp}. Regular expressions cannot
contain capturing groups, but can use non-capturing groups (?:pattern) instead. Optional wildcards (*{param}) do not
support regular expressions. Regexp support is opt-in via fox.AllowRegexpParam(true) option.
Pattern /src/+{filepath:[A-Za-z/]+\.json}
/src/dir/config.json matches
/src/dir/config.txt no matches
Route matchers
Route matchers enable routing decisions based on request properties beyond methods, hostname and path. Multiple routes can share the same pattern and methods and be differentiated by query parameters, headers, client IP, or custom criteria.
f.MustAdd(fox.MethodGet, "/api/users", V1Handler, fox.WithHeaderMatcher("X-API-Version", "v1"))
f.MustAdd(fox.MethodGet, "/api/users", V2Handler, fox.WithHeaderMatcher("X-API-Version", "v2"))
f.MustAdd(fox.MethodGet, "/api/users", V1Handler) // Fallback route
Built-in matchers include fox.WithQueryMatcher, fox.WithQueryRegexpMatcher, fox.WithHeaderMatcher, fox.WithHeaderRegexpMatcher,
and fox.WithClientIPMatcher. Multiple matchers on a route use AND logic. Routes without matchers serve as fallbacks.
For custom matching logic, implement the fox.Matcher interface and use fox.WithMatcher. See Priority rules for matcher
evaluation order.
Method-less routes
Route
