Files
fiber/adapter.go
2026-01-25 00:05:15 -05:00

276 lines
6.9 KiB
Go

package fiber
import (
"fmt"
"net/http"
"reflect"
"github.com/valyala/fasthttp"
"github.com/valyala/fasthttp/fasthttpadaptor"
)
// toFiberHandler converts a supported handler type to a Fiber handler.
func toFiberHandler(handler any) (Handler, bool) {
if handler == nil {
return nil, false
}
switch handler.(type) {
case Handler, func(Ctx): // (1)-(2) Fiber handlers
return adaptFiberHandler(handler)
case func(Req, Res) error, func(Req, Res), func(Req, Res, func() error) error, func(Req, Res, func() error), func(Req, Res, func()) error, func(Req, Res, func()), func(Req, Res, func(error)), func(Req, Res, func(error)) error, func(Req, Res, func(error) error), func(Req, Res, func(error) error) error: // (3)-(12) Express-style request handlers
return adaptExpressHandler(handler)
case http.HandlerFunc, http.Handler, func(http.ResponseWriter, *http.Request): // (13)-(15) net/http handlers
return adaptHTTPHandler(handler)
case fasthttp.RequestHandler, func(*fasthttp.RequestCtx) error: // (16)-(17) fasthttp handlers
return adaptFastHTTPHandler(handler)
default: // (18) unsupported handler type
return nil, false
}
}
func adaptFiberHandler(handler any) (Handler, bool) {
switch h := handler.(type) {
case Handler: // (1) direct Fiber handler
if h == nil {
return nil, false
}
return h, true
case func(Ctx): // (2) Fiber handler without error return
if h == nil {
return nil, false
}
return func(c Ctx) error {
h(c)
return nil
}, true
default:
return nil, false
}
}
func adaptExpressHandler(handler any) (Handler, bool) {
switch h := handler.(type) {
case func(Req, Res) error: // (3) Express-style handler with error return
if h == nil {
return nil, false
}
return func(c Ctx) error {
return h(c.Req(), c.Res())
}, true
case func(Req, Res): // (4) Express-style handler without error return
if h == nil {
return nil, false
}
return func(c Ctx) error {
h(c.Req(), c.Res())
return nil
}, true
case func(Req, Res, func() error) error: // (5) Express-style handler with error-returning next callback and error return
if h == nil {
return nil, false
}
return func(c Ctx) error {
return h(c.Req(), c.Res(), func() error {
return c.Next()
})
}, true
case func(Req, Res, func() error): // (6) Express-style handler with error-returning next callback
if h == nil {
return nil, false
}
return func(c Ctx) error {
var nextErr error
h(c.Req(), c.Res(), func() error {
nextErr = c.Next()
return nextErr
})
return nextErr
}, true
case func(Req, Res, func()) error: // (7) Express-style handler with no-arg next callback and error return
if h == nil {
return nil, false
}
return func(c Ctx) error {
var nextErr error
err := h(c.Req(), c.Res(), func() {
nextErr = c.Next()
})
if err != nil {
return err
}
return nextErr
}, true
case func(Req, Res, func()): // (8) Express-style handler with no-arg next callback
if h == nil {
return nil, false
}
return func(c Ctx) error {
var nextErr error
h(c.Req(), c.Res(), func() {
nextErr = c.Next()
})
return nextErr
}, true
case func(Req, Res, func(error)): // (9) Express-style handler with error-accepting next callback
if h == nil {
return nil, false
}
return func(c Ctx) error {
var nextErr error
h(c.Req(), c.Res(), func(err error) {
if err != nil {
nextErr = err
return
}
nextErr = c.Next()
})
return nextErr
}, true
case func(Req, Res, func(error)) error: // (10) Express-style handler with error-accepting next callback and error return
if h == nil {
return nil, false
}
return func(c Ctx) error {
var nextErr error
err := h(c.Req(), c.Res(), func(nextErrArg error) {
if nextErrArg != nil {
nextErr = nextErrArg
return
}
nextErr = c.Next()
})
if err != nil {
return err
}
return nextErr
}, true
case func(Req, Res, func(error) error): // (11) Express-style handler with error-accepting next callback that returns an error
if h == nil {
return nil, false
}
return func(c Ctx) error {
var nextErr error
h(c.Req(), c.Res(), func(nextErrArg error) error {
if nextErrArg != nil {
nextErr = nextErrArg
return nextErrArg
}
nextErr = c.Next()
return nextErr
})
return nextErr
}, true
case func(Req, Res, func(error) error) error: // (12) Express-style handler with error-accepting next callback that returns an error and error return
if h == nil {
return nil, false
}
return func(c Ctx) error {
var nextErr error
err := h(c.Req(), c.Res(), func(nextErrArg error) error {
if nextErrArg != nil {
nextErr = nextErrArg
return nextErrArg
}
nextErr = c.Next()
return nextErr
})
if err != nil {
return err
}
return nextErr
}, true
default:
return nil, false
}
}
func adaptHTTPHandler(handler any) (Handler, bool) {
switch h := handler.(type) {
case http.HandlerFunc: // (13) net/http HandlerFunc
if h == nil {
return nil, false
}
return wrapHTTPHandler(h), true
case http.Handler: // (14) net/http Handler implementation
if h == nil {
return nil, false
}
hv := reflect.ValueOf(h)
if isNilableKind(hv.Kind()) && hv.IsNil() {
return nil, false
}
return wrapHTTPHandler(h), true
case func(http.ResponseWriter, *http.Request): // (15) net/http function handler
if h == nil {
return nil, false
}
return wrapHTTPHandler(http.HandlerFunc(h)), true
default:
return nil, false
}
}
func isNilableKind(kind reflect.Kind) bool {
switch kind {
case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.Interface, reflect.Slice, reflect.UnsafePointer:
return true
default:
return false
}
}
func adaptFastHTTPHandler(handler any) (Handler, bool) {
switch h := handler.(type) {
case fasthttp.RequestHandler: // (16) fasthttp handler
if h == nil {
return nil, false
}
return func(c Ctx) error {
h(c.RequestCtx())
return nil
}, true
case func(*fasthttp.RequestCtx) error: // (17) fasthttp handler with error return
if h == nil {
return nil, false
}
return func(c Ctx) error {
return h(c.RequestCtx())
}, true
default:
return nil, false
}
}
// wrapHTTPHandler adapts a net/http handler to a Fiber handler.
func wrapHTTPHandler(handler http.Handler) Handler {
if handler == nil {
return nil
}
adapted := fasthttpadaptor.NewFastHTTPHandler(handler)
return func(c Ctx) error {
adapted(c.RequestCtx())
return nil
}
}
// collectHandlers converts a slice of handler arguments to Fiber handlers.
// The context string is used to provide informative panic messages when an
// unsupported handler type is encountered.
func collectHandlers(context string, args ...any) []Handler {
handlers := make([]Handler, 0, len(args))
for i, arg := range args {
handler, ok := toFiberHandler(arg)
if !ok {
panic(fmt.Sprintf("%s: invalid handler #%d (%T)\n", context, i, arg))
}
handlers = append(handlers, handler)
}
return handlers
}