Adapters (overview)
In jetwarp, an adapter is the entry-point you use in application code.
An adapter gives you a single, stable API (adapter.Adapter) while delegating the actual routing to a pluggable driver under the hood. Your handlers stay standard net/http (http.Handler / http.HandlerFunc), and you can swap the underlying router framework (stdlib, chi, gin, echo, fiber, …) without rewriting your app.
What an adapter gives you
1) A portable router API
All adapters return the same interface:
Use(...)global middlewareGroup(prefix, ...)scoped prefix + middlewareWith(...)scoped middleware without changing the prefixHandle(...)/HandleFunc(...)route registrationErr()accumulated registration errors- plus
ServeHTTPso the router itself is anhttp.Handler
This is the only surface your application should depend on.
2) A strict “no panic” setup experience
Jetwarp treats route registration as input validation, not a crash site:
- Invalid patterns, unsupported features, or driver failures must accumulate as errors
- The router must remain usable even after a bad registration
- You check
r.Err()once your setup is done (before serving traffic)
3) Thin packaging (you only pull what you use)
Each adapter lives in its own module (for example adapter/chi, adapter/gin, …), so you don’t
download every framework dependency just to use one.
Choosing an adapter
There is no “best” adapter — pick what matches your project and team.
| Adapter | Good default when… | Notes |
|---|---|---|
stdlib | you want the smallest surface area, maximum portability | Based on net/http routing semantics |
chi | you already use chi, or you want a small, idiomatic router | Strong feature set, common in Go services |
gin | you’re in the gin ecosystem | Jetwarp wraps gin while keeping net/http handlers |
echo | you’re in the echo ecosystem | Jetwarp wraps echo while keeping net/http handlers |
fiber | you want Fiber’s performance model / ecosystem | Jetwarp bridges Fiber (not net/http native) to net/http handlers |
If you’re not sure, start with stdlib or chi. You can always change later — that’s the point.
Using an adapter
Adapters intentionally keep construction boring:
package main
import (
"log"
"net/http"
"codeberg.org/iaconlabs/jetwarp/adapter/chi"
)
func main() {
r := chi.New()
r.HandleFunc(http.MethodGet, "/healthz", func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("OK"))
})
if err := r.Err(); err != nil {
log.Fatal(err)
}
log.Fatal(http.ListenAndServe(":8080", r))
}
That same application code should work with adapter/stdlib, adapter/gin, adapter/echo, adapter/fiber, etc. (only the import + constructor change).
Middleware support
Jetwarp middleware is expressed via adapter.MW.
Portable middleware
Portable middleware wraps standard net/http middleware (func(http.Handler) http.Handler) and works everywhere:
mw := adapter.HTTP(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// before
next.ServeHTTP(w, r)
// after
})
})
r.Use(mw)
Native middleware (framework-specific)
Jetwarp has a design for native/driver middleware, but not every adapter/driver can express it.
If a middleware cannot be applied portably, jetwarp will record an error and continue setup (you’ll see it in Err()).
As a rule of thumb: if you want maximum portability, keep middleware portable.
Reading path parameters
Jetwarp’s canonical pattern syntax uses {name} parameters (e.g. /users/{id}), but how you read the value inside a handler depends on the underlying router.
Many adapters bridge parameters into the standard library *http.Request API (r.PathValue("id")) for a consistent user experience. Some frameworks don’t expose this natively, so bridging is handled at the driver level where possible.
If your service depends heavily on params, test your chosen adapter(s) early and keep your handler param access strategy consistent across the project. (Driver capabilities and param rules are covered in the Drivers section of the docs.)
Introspection and escape hatches (optional)
Most application code should never need these, but they exist for tooling and debugging.
Registry snapshots
Some adapter implementations also expose a registry snapshot (the “truth source” for OpenAPI, diagnostics, and other tooling). When supported, you’ll access it via a type assertion to the appropriate optional interface documented in the adapter package.
Engine access
Similarly, some adapters expose the underlying router/engine as any (for debugging or very specific integrations). This is intentionally an escape hatch — if you rely on it, you are stepping outside the portability contract.
Conformance: why adapters are trusted
Jetwarp’s portability promise is enforced by a shared conformance suite (tests/suite). Drivers must pass driver conformance tests for the capabilities they claim. Adapters are also exercised against adapter-level conformance. If something “works in gin but not in chi”, that’s either:
-
a capability you relied on that one adapter doesn’t claim/support, or
-
a bug (and the suite is where we pin it).