Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions adapters/adapters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import (
"github.com/danielgtaylor/huma/v2/humatest"
"github.com/gin-gonic/gin"
"github.com/go-chi/chi/v5"
"github.com/gofiber/fiber/v2"
fiberV2 "github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/gorilla/mux"
"github.com/julienschmidt/httprouter"
"github.com/labstack/echo/v4"
Expand Down Expand Up @@ -103,7 +104,8 @@ func TestAdapters(t *testing.T) {
assert.Equal(t, 1, v.ProtoMajor)
assert.Equal(t, 1, v.ProtoMinor)
} else {
assert.Equal(t, "http", v.Proto)
// Fiber adapters (both v2 and v3) don't populate ProtoMajor/ProtoMinor
assert.Contains(t, []string{"http", "HTTP/1.1"}, v.Proto)
}

// Make sure huma.WithValue works correctly
Expand Down Expand Up @@ -131,6 +133,9 @@ func TestAdapters(t *testing.T) {
{"fiber", func() huma.API {
return wrap(humafiber.New(fiber.New(), config()), true, func(ctx huma.Context) { humafiber.Unwrap(ctx) })
}},
{"fiber-v2", func() huma.API {
return wrap(humafiber.NewV2(fiberV2.New(), config()), true, func(ctx huma.Context) { humafiber.UnwrapV2(ctx) })
}},
{"go", func() huma.API {
return wrap(humago.New(http.NewServeMux(), config()), false, func(ctx huma.Context) { humago.Unwrap(ctx) })
}},
Expand Down
33 changes: 17 additions & 16 deletions adapters/humafiber/humafiber.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ import (
"time"

"github.com/danielgtaylor/huma/v2"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
)

// Unwrap extracts the underlying Fiber context from a Huma context. If passed a
// context from a different adapter it will panic. Keep in mind the limitations
// of the underlying Fiber/fasthttp libraries and how that impacts
// memory-safety: https://docs.gofiber.io/#zero-allocation. Do not keep
// references to the underlying context or its values!
func Unwrap(ctx huma.Context) *fiber.Ctx {
func Unwrap(ctx huma.Context) fiber.Ctx {
for {
if c, ok := ctx.(interface{ Unwrap() huma.Context }); ok {
ctx = c.Unwrap()
Expand All @@ -42,14 +42,14 @@ type fiberAdapter struct {
type fiberWrapper struct {
op *huma.Operation
status int
orig *fiber.Ctx
orig fiber.Ctx
Comment thread
wolveix marked this conversation as resolved.
ctx context.Context
}

// check that fiberCtx implements huma.Context
// check that fiberWrapper implements huma.Context
var _ huma.Context = &fiberWrapper{}

func (c *fiberWrapper) Unwrap() *fiber.Ctx {
func (c *fiberWrapper) Unwrap() fiber.Ctx {
return c.orig
}

Expand All @@ -74,7 +74,7 @@ func (c *fiberWrapper) Host() string {
}

func (c *fiberWrapper) RemoteAddr() string {
return c.orig.Context().RemoteAddr().String()
return c.orig.RequestCtx().RemoteAddr().String()
}

func (c *fiberWrapper) URL() url.URL {
Expand Down Expand Up @@ -120,7 +120,7 @@ func (c *fiberWrapper) SetReadDeadline(deadline time.Time) error {
// 2. Set the Fiber app's `BodyLimit` to some small value like `1`
// Fiber will only call the request handler for streaming once the limit is
// reached. This is annoying but currently how things work.
return c.orig.Context().Conn().SetReadDeadline(deadline)
return c.orig.RequestCtx().Conn().SetReadDeadline(deadline)
}

func (c *fiberWrapper) SetStatus(code int) {
Expand All @@ -132,6 +132,7 @@ func (c *fiberWrapper) SetStatus(code int) {
func (c *fiberWrapper) Status() int {
return c.status
}

func (c *fiberWrapper) AppendHeader(name string, value string) {
c.orig.Append(name, value)
}
Expand All @@ -141,11 +142,11 @@ func (c *fiberWrapper) SetHeader(name string, value string) {
}

func (c *fiberWrapper) BodyWriter() io.Writer {
return c.orig.Context()
return c.orig.RequestCtx()
}

func (c *fiberWrapper) TLS() *tls.ConnectionState {
return c.orig.Context().TLSConnectionState()
return c.orig.RequestCtx().TLSConnectionState()
}

func (c *fiberWrapper) Version() huma.ProtoVersion {
Expand All @@ -155,11 +156,11 @@ func (c *fiberWrapper) Version() huma.ProtoVersion {
}

type router interface {
Add(method, path string, handlers ...fiber.Handler) fiber.Router
Add(methods []string, path string, handler any, handlers ...any) fiber.Router
Comment thread
wolveix marked this conversation as resolved.
}

type requestTester interface {
Test(*http.Request, ...int) (*http.Response, error)
Test(*http.Request, ...fiber.TestConfig) (*http.Response, error)
Comment thread
wolveix marked this conversation as resolved.
}

type contextWrapperValue struct {
Expand Down Expand Up @@ -194,9 +195,9 @@ func (a *fiberAdapter) Handle(op *huma.Operation, handler func(huma.Context)) {
path := op.Path
path = strings.ReplaceAll(path, "{", ":")
path = strings.ReplaceAll(path, "}", "")
a.router.Add(op.Method, path, func(c *fiber.Ctx) error {
a.router.Add([]string{op.Method}, path, func(c fiber.Ctx) error {
var values []*contextWrapperValue
c.Context().VisitUserValuesAll(func(key, value any) {
c.RequestCtx().VisitUserValuesAll(func(key, value any) {
values = append(values, &contextWrapperValue{
Key: key,
Value: value,
Expand All @@ -207,16 +208,14 @@ func (a *fiberAdapter) Handle(op *huma.Operation, handler func(huma.Context)) {
orig: c,
ctx: &contextWrapper{
values: values,
Context: c.UserContext(),
Context: c.Context(),
},
})
return nil
})
}

func (a *fiberAdapter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// b, _ := httputil.DumpRequest(r, true)
// fmt.Println(string(b))
resp, err := a.tester.Test(r)
if resp != nil && resp.Body != nil {
defer func() {
Expand All @@ -236,10 +235,12 @@ func (a *fiberAdapter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
_, _ = io.Copy(w, resp.Body)
}

// New creates a new Huma API using the Fiber adapter.
func New(r *fiber.App, config huma.Config) huma.API {
return huma.NewAPI(config, &fiberAdapter{tester: r, router: r})
}

// NewWithGroup creates a new Huma API using the Fiber adapter with a route group.
func NewWithGroup(r *fiber.App, g fiber.Router, config huma.Config) huma.API {
return huma.NewAPI(config, &fiberAdapter{tester: r, router: g})
}
20 changes: 9 additions & 11 deletions adapters/humafiber/humafiber_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/adapters/humafiber"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -64,7 +64,7 @@ const (
HelloPath = "/hello"
)

func PingHandler(c *fiber.Ctx) error {
func PingHandler(c fiber.Ctx) error {
return c.SendStatus(fiber.StatusOK)
}

Expand Down Expand Up @@ -192,21 +192,21 @@ func HelloResponseValidate(t *testing.T, expected HelloResponseBody, response *h
}
}

func FiberMiddlewareUserValue(c *fiber.Ctx) error {
func FiberMiddlewareUserValue(c fiber.Ctx) error {
headers := c.GetReqHeaders()
if values, found := headers[HeaderNameFiberUserValue]; found && len(values) > 0 {
c.Context().SetUserValue(contextValueFiberUserValue, values[0])
c.Locals(contextValueFiberUserValue, values[0])
}
return c.Next()
}

func FiberMiddlewareUserContext(c *fiber.Ctx) error {
func FiberMiddlewareUserContext(c fiber.Ctx) error {
headers := c.GetReqHeaders()
if values, found := headers[HeaderNameFiberUserContext]; found && len(values) > 0 {
var original = c.UserContext()
var original = c.Context()
var result = context.WithValue(original, contextValueFiberUserContext, values[0])
c.SetUserContext(result)
defer c.SetUserContext(original)
c.SetContext(result)
defer c.SetContext(original)
}
return c.Next()
}
Expand Down Expand Up @@ -236,9 +236,7 @@ func TestHumaFiber(t *testing.T) {
require.NotZero(t, port)
server := fmt.Sprintf("http://localhost:%d", port)

app := fiber.New(fiber.Config{
DisableStartupMessage: true,
})
app := fiber.New()
app.Use(FiberMiddlewareUserValue)
app.Use(FiberMiddlewareUserContext)
RegisterPing(app)
Expand Down
4 changes: 2 additions & 2 deletions adapters/humafiber/humafiber_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"testing"

"github.com/danielgtaylor/huma/v2"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v3"
)

func BenchmarkHumaFiber(b *testing.B) {
Expand Down Expand Up @@ -48,7 +48,7 @@ func BenchmarkNotHuma(b *testing.B) {

r := fiber.New()

r.Get("/foo/:id", func(c *fiber.Ctx) error {
r.Get("/foo/:id", func(c fiber.Ctx) error {
return c.JSON(&GreetingOutput{"Hello, " + c.Params("id")})
})

Expand Down
Loading