From 79c190d672d4b206f3e963cf8b788db97d33d252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Mouton?= Date: Fri, 22 May 2026 19:19:12 +0200 Subject: [PATCH 1/4] Update dependencies and migrate to Fiber v3 - Updated go.sum to use github.com/gofiber/fiber/v3 and other dependencies. - Refactored group.go, group_test.go, and other test files to accommodate the new Fiber v3 API. - Adjusted handler signatures in various test files to match the new Fiber v3 context type. - Added a utility function to convert fiber.Handler to any type for compatibility with Fiber v3. - Ensured all tests pass with the updated Fiber version. --- README.md | 14 ++--- _examples/auth/go.mod | 33 ++++++----- _examples/auth/go.sum | 62 ++++++++++++--------- _examples/auth/main.go | 22 ++++---- _examples/auto_params/go.mod | 33 ++++++----- _examples/auto_params/go.sum | 62 ++++++++++++--------- _examples/auto_params/main.go | 6 +- _examples/custom_validation_error/README.md | 6 +- _examples/custom_validation_error/go.mod | 33 ++++++----- _examples/custom_validation_error/go.sum | 62 ++++++++++++--------- _examples/custom_validation_error/main.go | 8 +-- _examples/simple/go.mod | 33 ++++++----- _examples/simple/go.sum | 62 ++++++++++++--------- _examples/simple/main.go | 14 ++--- auth.go | 14 ++--- auth_middleware_test.go | 14 ++--- auth_schemes.go | 14 ++--- auth_schemes_test.go | 60 ++++++++++---------- auth_test.go | 34 +++++------ auto_params_edge_cases_test.go | 12 ++-- auto_params_test.go | 10 ++-- common.go | 14 ++--- conditional_auth.go | 12 ++-- config_test.go | 2 +- custom_validation_error_test.go | 20 +++---- delete_test.go | 16 +++--- docs.go | 10 ++-- docs_test.go | 4 +- fiberoapi.go | 16 +++--- get_oapi_test.go | 22 ++++---- go.mod | 27 +++++---- go.sum | 54 ++++++++++-------- group.go | 17 ++++-- group_test.go | 8 +-- header_params_test.go | 16 +++--- json_type_error_test.go | 12 ++-- nested_struct_test.go | 8 +-- openapi_hidden_test.go | 6 +- post_test.go | 14 ++--- put_test.go | 12 ++-- serialization_error_test.go | 6 +- time_type_test.go | 16 +++--- types.go | 8 +-- validation_test.go | 8 +-- 44 files changed, 503 insertions(+), 433 deletions(-) diff --git a/README.md b/README.md index 8f5f22b..190ecc5 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ A Go library that extends Fiber to add automatic OpenAPI documentation generatio ## Installation ```bash -go get github.com/labbs/fiber-oapi +go get github.com/labbs/fiber-oapi/v3 ``` ## Quick Start @@ -30,8 +30,8 @@ go get github.com/labbs/fiber-oapi package main import ( - "github.com/gofiber/fiber/v2" - fiberoapi "github.com/labbs/fiber-oapi" + "github.com/gofiber/fiber/v3" + fiberoapi "github.com/labbs/fiber-oapi/v3" ) func main() { @@ -39,7 +39,7 @@ func main() { oapi := fiberoapi.New(app) fiberoapi.Get(oapi, "/hello/:name", - func(c *fiber.Ctx, input struct { + func(c fiber.Ctx, input struct { Name string `path:"name" validate:"required,min=2"` }) (fiber.Map, *fiberoapi.ErrorResponse) { return fiber.Map{"message": "Hello " + input.Name}, nil @@ -299,7 +299,7 @@ fiberoapi.RequireResourceAccess(c, authService, "document", docID, "delete") Access the authenticated user in handlers: ```go -fiberoapi.Get(oapi, "/me", func(c *fiber.Ctx, input struct{}) (fiber.Map, *fiberoapi.ErrorResponse) { +fiberoapi.Get(oapi, "/me", func(c fiber.Ctx, input struct{}) (fiber.Map, *fiberoapi.ErrorResponse) { authCtx, err := fiberoapi.GetAuthContext(c) if err != nil { return nil, &fiberoapi.ErrorResponse{Code: 401, Details: "Not authenticated"} @@ -319,7 +319,7 @@ fiberoapi.Get(oapi, "/me", func(c *fiber.Ctx, input struct{}) (fiber.Map, *fiber ```go oapi := fiberoapi.New(app, fiberoapi.Config{ - ValidationErrorHandler: func(c *fiber.Ctx, err error) error { + ValidationErrorHandler: func(c fiber.Ctx, err error) error { return c.Status(400).JSON(fiber.Map{ "success": false, "error": err.Error(), @@ -334,7 +334,7 @@ oapi := fiberoapi.New(app, fiberoapi.Config{ oapi := fiberoapi.New(app, fiberoapi.Config{ EnableAuthorization: true, AuthService: authService, - AuthErrorHandler: func(c *fiber.Ctx, err *fiberoapi.AuthError) error { + AuthErrorHandler: func(c fiber.Ctx, err *fiberoapi.AuthError) error { // err.StatusCode: 401, 403, or 5xx // err.Message: human-readable error message return c.Status(err.StatusCode).JSON(fiber.Map{ diff --git a/_examples/auth/go.mod b/_examples/auth/go.mod index 9d650dc..db10eef 100644 --- a/_examples/auth/go.mod +++ b/_examples/auth/go.mod @@ -1,31 +1,34 @@ module auth -go 1.24.2 +go 1.26.0 -replace github.com/Labbs/fiber-oapi => ../../ +replace github.com/labbs/fiber-oapi/v3 => ../../ require ( - github.com/Labbs/fiber-oapi v0.0.0-00010101000000-000000000000 - github.com/gofiber/fiber/v2 v2.52.12 + github.com/gofiber/fiber/v3 v3.3.0 + github.com/labbs/fiber-oapi/v3 v3.0.0-00010101000000-000000000000 ) require ( - github.com/andybalholm/brotli v1.2.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.12 // indirect + github.com/andybalholm/brotli v1.2.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.13 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.30.1 // indirect + github.com/go-playground/validator/v10 v10.30.2 // indirect + github.com/gofiber/schema v1.7.1 // indirect + github.com/gofiber/utils/v2 v2.0.6 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.17 // indirect - github.com/rivo/uniseg v0.4.7 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/philhofer/fwd v1.2.0 // indirect + github.com/tinylib/msgp v1.6.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.66.0 // indirect - golang.org/x/crypto v0.46.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.32.0 // indirect + github.com/valyala/fasthttp v1.71.0 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.54.0 // indirect + golang.org/x/sys v0.44.0 // indirect + golang.org/x/text v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/_examples/auth/go.sum b/_examples/auth/go.sum index 432c529..f2ae6bb 100644 --- a/_examples/auth/go.sum +++ b/_examples/auth/go.sum @@ -1,51 +1,61 @@ -github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= -github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro= +github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= -github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78= +github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= +github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= -github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= -github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= -github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ= +github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc= +github.com/gofiber/fiber/v3 v3.3.0 h1:QBd3sYCqdy6Qs5gJYzSw4I4SbqL204jPqpdub/ueiw8= +github.com/gofiber/fiber/v3 v3.3.0/go.mod h1:YH7/TAoRaU4kF8slDCtQuFJ1NzC+3MtxUI4KfvQtaIA= +github.com/gofiber/schema v1.7.1 h1:oSJBKdgP8JeIME4TQSAqlNKTU2iBB+2RNmKi8Nsc+TI= +github.com/gofiber/schema v1.7.1/go.mod h1:A/X5Ffyru4p9eBdp99qu+nzviHzQiZ7odLT+TwxWhbk= +github.com/gofiber/utils/v2 v2.0.6 h1:7fXYy7nSsyqbH0GQUMtK4Kwjy4J7R5742VM7JsZxzOs= +github.com/gofiber/utils/v2 v2.0.6/go.mod h1:p7mAHAk3+oUK10ZX2xTw9fZQixb4hCg8SKd4IH2xroU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.17 h1:78v8ZlW0bP43XfmAfPsdXcoNCelfMHsDmd/pkENfrjQ= -github.com/mattn/go-runewidth v0.0.17/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= +github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/shamaton/msgpack/v3 v3.1.2 h1:d5gWAIyMU4M0WgDjz6IFSCuXJUA2dFwRHBpDclE8CLw= +github.com/shamaton/msgpack/v3 v3.1.2/go.mod h1:DcQG8jrdrQCIxr3HlMYkiXdMhK+KfN2CitkyzsQV4uc= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ= +github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.66.0 h1:M87A0Z7EayeyNaV6pfO3tUTUiYO0dZfEJnRGXTVNuyU= -github.com/valyala/fasthttp v1.66.0/go.mod h1:Y4eC+zwoocmXSVCB1JmhNbYtS7tZPRI2ztPB72EVObs= +github.com/valyala/fasthttp v1.71.0 h1:tepR7H+Guh9VUqxxcPggYi8R3lGUu2Rsdh+z7/FCY3k= +github.com/valyala/fasthttp v1.71.0/go.mod h1:z1sDUvOShhXq/C9mwH/fSm1Vb71tUJwmQdgkBrBNwnA= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/_examples/auth/main.go b/_examples/auth/main.go index 6760cc6..955bbdb 100644 --- a/_examples/auth/main.go +++ b/_examples/auth/main.go @@ -4,8 +4,8 @@ import ( "fmt" "time" - fiberoapi "github.com/Labbs/fiber-oapi" - "github.com/gofiber/fiber/v2" + fiberoapi "github.com/labbs/fiber-oapi/v3" + "github.com/gofiber/fiber/v3" ) // Authentication service with role management. @@ -241,7 +241,7 @@ func main() { EnableAuthorization: true, AuthService: authService, // Custom error handler for authentication/authorization errors - AuthErrorHandler: func(c *fiber.Ctx, err *fiberoapi.AuthError) error { + AuthErrorHandler: func(c fiber.Ctx, err *fiberoapi.AuthError) error { errType := "authentication_error" if err.StatusCode == 403 { errType = "authorization_error" @@ -290,7 +290,7 @@ func main() { // ====== ROUTES PUBLIQUES ====== fiberoapi.Get(oapi, "/health", - func(c *fiber.Ctx, input struct{}) (map[string]string, *fiberoapi.ErrorResponse) { + func(c fiber.Ctx, input struct{}) (map[string]string, *fiberoapi.ErrorResponse) { return map[string]string{ "status": "ok", "service": "fiber-oapi auth example", @@ -306,7 +306,7 @@ func main() { // ====== ROUTES AVEC AUTHENTIFICATION SIMPLE ====== fiberoapi.Get(oapi, "/me", - func(c *fiber.Ctx, input struct{}) (CreateUserResponse, *fiberoapi.ErrorResponse) { + func(c fiber.Ctx, input struct{}) (CreateUserResponse, *fiberoapi.ErrorResponse) { authCtx, _ := fiberoapi.GetAuthContext(c) return CreateUserResponse{ ID: 1, @@ -322,7 +322,7 @@ func main() { // Test endpoint with map[string]interface{} response fiberoapi.Get(oapi, "/status", - func(c *fiber.Ctx, input struct{}) (map[string]interface{}, *fiberoapi.ErrorResponse) { + func(c fiber.Ctx, input struct{}) (map[string]interface{}, *fiberoapi.ErrorResponse) { authCtx, _ := fiberoapi.GetAuthContext(c) return map[string]interface{}{ "user_id": authCtx.UserID, @@ -348,7 +348,7 @@ func main() { // RequiredRoles: vérifié automatiquement avant le handler // RequiredPermissions: documenté dans la spec OpenAPI fiberoapi.Get(oapi, "/documents/:documentId", - func(c *fiber.Ctx, input DocumentRequest) (DocumentResponse, *fiberoapi.ErrorResponse) { + func(c fiber.Ctx, input DocumentRequest) (DocumentResponse, *fiberoapi.ErrorResponse) { authCtx, _ := fiberoapi.GetAuthContext(c) fmt.Printf("📖 User %s (roles: %v) accessing document %s\n", authCtx.UserID, authCtx.Roles, input.DocumentID) @@ -369,7 +369,7 @@ func main() { // Route pour les éditeurs (peuvent modifier) fiberoapi.Put(oapi, "/documents/:documentId", - func(c *fiber.Ctx, input UpdateDocumentRequest) (DocumentResponse, *fiberoapi.ErrorResponse) { + func(c fiber.Ctx, input UpdateDocumentRequest) (DocumentResponse, *fiberoapi.ErrorResponse) { authCtx, _ := fiberoapi.GetAuthContext(c) fmt.Printf("✏️ User %s (scopes: %v) updating document %s\n", authCtx.UserID, authCtx.Scopes, input.DocumentID) @@ -390,7 +390,7 @@ func main() { // Route pour partager (éditeurs seulement) fiberoapi.Post(oapi, "/documents/:documentId/share", - func(c *fiber.Ctx, input DocumentRequest) (DocumentShareResponse, *fiberoapi.ErrorResponse) { + func(c fiber.Ctx, input DocumentRequest) (DocumentShareResponse, *fiberoapi.ErrorResponse) { authCtx, _ := fiberoapi.GetAuthContext(c) fmt.Printf("🔗 User %s sharing document %s\n", authCtx.UserID, input.DocumentID) @@ -408,7 +408,7 @@ func main() { // Route réservée aux administrateurs fiberoapi.Delete(oapi, "/documents/:documentId", - func(c *fiber.Ctx, input DocumentRequest) (DocumentDeleteResponse, *fiberoapi.ErrorResponse) { + func(c fiber.Ctx, input DocumentRequest) (DocumentDeleteResponse, *fiberoapi.ErrorResponse) { authCtx, _ := fiberoapi.GetAuthContext(c) fmt.Printf("🗑️ Admin %s deleting document %s\n", authCtx.UserID, input.DocumentID) @@ -426,7 +426,7 @@ func main() { // Route de création d'utilisateur (admin seulement) fiberoapi.Post(oapi, "/users", - func(c *fiber.Ctx, input CreateUserRequest) (CreateUserResponse, *fiberoapi.ErrorResponse) { + func(c fiber.Ctx, input CreateUserRequest) (CreateUserResponse, *fiberoapi.ErrorResponse) { authCtx, _ := fiberoapi.GetAuthContext(c) fmt.Printf("👤 Admin %s creating user: %s\n", authCtx.UserID, input.Name) diff --git a/_examples/auto_params/go.mod b/_examples/auto_params/go.mod index 594d91b..8ab1720 100644 --- a/_examples/auto_params/go.mod +++ b/_examples/auto_params/go.mod @@ -1,31 +1,34 @@ module demo -go 1.24.2 +go 1.26.0 -replace github.com/labbs/fiber-oapi => ../.. +replace github.com/labbs/fiber-oapi/v3 => ../.. require ( - github.com/gofiber/fiber/v2 v2.52.12 - github.com/labbs/fiber-oapi v0.0.0-00010101000000-000000000000 + github.com/gofiber/fiber/v3 v3.3.0 + github.com/labbs/fiber-oapi/v3 v3.0.0-00010101000000-000000000000 ) require ( - github.com/andybalholm/brotli v1.2.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.12 // indirect + github.com/andybalholm/brotli v1.2.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.13 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.30.1 // indirect + github.com/go-playground/validator/v10 v10.30.2 // indirect + github.com/gofiber/schema v1.7.1 // indirect + github.com/gofiber/utils/v2 v2.0.6 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.17 // indirect - github.com/rivo/uniseg v0.4.7 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/philhofer/fwd v1.2.0 // indirect + github.com/tinylib/msgp v1.6.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.66.0 // indirect - golang.org/x/crypto v0.46.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.32.0 // indirect + github.com/valyala/fasthttp v1.71.0 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.54.0 // indirect + golang.org/x/sys v0.44.0 // indirect + golang.org/x/text v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/_examples/auto_params/go.sum b/_examples/auto_params/go.sum index 432c529..f2ae6bb 100644 --- a/_examples/auto_params/go.sum +++ b/_examples/auto_params/go.sum @@ -1,51 +1,61 @@ -github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= -github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro= +github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= -github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78= +github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= +github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= -github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= -github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= -github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ= +github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc= +github.com/gofiber/fiber/v3 v3.3.0 h1:QBd3sYCqdy6Qs5gJYzSw4I4SbqL204jPqpdub/ueiw8= +github.com/gofiber/fiber/v3 v3.3.0/go.mod h1:YH7/TAoRaU4kF8slDCtQuFJ1NzC+3MtxUI4KfvQtaIA= +github.com/gofiber/schema v1.7.1 h1:oSJBKdgP8JeIME4TQSAqlNKTU2iBB+2RNmKi8Nsc+TI= +github.com/gofiber/schema v1.7.1/go.mod h1:A/X5Ffyru4p9eBdp99qu+nzviHzQiZ7odLT+TwxWhbk= +github.com/gofiber/utils/v2 v2.0.6 h1:7fXYy7nSsyqbH0GQUMtK4Kwjy4J7R5742VM7JsZxzOs= +github.com/gofiber/utils/v2 v2.0.6/go.mod h1:p7mAHAk3+oUK10ZX2xTw9fZQixb4hCg8SKd4IH2xroU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.17 h1:78v8ZlW0bP43XfmAfPsdXcoNCelfMHsDmd/pkENfrjQ= -github.com/mattn/go-runewidth v0.0.17/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= +github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/shamaton/msgpack/v3 v3.1.2 h1:d5gWAIyMU4M0WgDjz6IFSCuXJUA2dFwRHBpDclE8CLw= +github.com/shamaton/msgpack/v3 v3.1.2/go.mod h1:DcQG8jrdrQCIxr3HlMYkiXdMhK+KfN2CitkyzsQV4uc= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ= +github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.66.0 h1:M87A0Z7EayeyNaV6pfO3tUTUiYO0dZfEJnRGXTVNuyU= -github.com/valyala/fasthttp v1.66.0/go.mod h1:Y4eC+zwoocmXSVCB1JmhNbYtS7tZPRI2ztPB72EVObs= +github.com/valyala/fasthttp v1.71.0 h1:tepR7H+Guh9VUqxxcPggYi8R3lGUu2Rsdh+z7/FCY3k= +github.com/valyala/fasthttp v1.71.0/go.mod h1:z1sDUvOShhXq/C9mwH/fSm1Vb71tUJwmQdgkBrBNwnA= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/_examples/auto_params/main.go b/_examples/auto_params/main.go index 709c00a..22f2a83 100644 --- a/_examples/auto_params/main.go +++ b/_examples/auto_params/main.go @@ -5,8 +5,8 @@ import ( "fmt" "log" - "github.com/gofiber/fiber/v2" - fiberoapi "github.com/labbs/fiber-oapi" + "github.com/gofiber/fiber/v3" + fiberoapi "github.com/labbs/fiber-oapi/v3" ) type SearchInput struct { @@ -47,7 +47,7 @@ func main() { oapi := fiberoapi.New(app) // Endpoint avec génération automatique des paramètres - fiberoapi.Get(oapi, "/users/:name", func(c *fiber.Ctx, input SearchInput) (SearchOutput, ErrorResponse) { + fiberoapi.Get(oapi, "/users/:name", func(c fiber.Ctx, input SearchInput) (SearchOutput, ErrorResponse) { // Simulate search results user := User{ ID: 1, diff --git a/_examples/custom_validation_error/README.md b/_examples/custom_validation_error/README.md index 00bd13c..ecf1a29 100644 --- a/_examples/custom_validation_error/README.md +++ b/_examples/custom_validation_error/README.md @@ -25,7 +25,7 @@ Use the `ValidationErrorHandler` field in the `Config` to provide a custom funct ```go // Minimal configuration - validation is automatically enabled oapi := fiberoapi.New(app, fiberoapi.Config{ - ValidationErrorHandler: func(c *fiber.Ctx, err error) error { + ValidationErrorHandler: func(c fiber.Ctx, err error) error { // Return your custom error structure return c.Status(fiber.StatusBadRequest).JSON(CustomErrorResponse{ Success: false, @@ -41,7 +41,7 @@ oapi := fiberoapi.New(app, fiberoapi.Config{ oapi := fiberoapi.New(app, fiberoapi.Config{ EnableValidation: true, EnableOpenAPIDocs: true, - ValidationErrorHandler: func(c *fiber.Ctx, err error) error { + ValidationErrorHandler: func(c fiber.Ctx, err error) error { return c.Status(fiber.StatusBadRequest).JSON(CustomErrorResponse{ Success: false, Message: err.Error(), @@ -118,7 +118,7 @@ curl -X POST http://localhost:3000/users \ You can also parse the validation error to extract detailed information: ```go -ValidationErrorHandler: func(c *fiber.Ctx, err error) error { +ValidationErrorHandler: func(c fiber.Ctx, err error) error { // Parse validator errors for more details if validationErrs, ok := err.(validator.ValidationErrors); ok { errors := make([]map[string]string, 0) diff --git a/_examples/custom_validation_error/go.mod b/_examples/custom_validation_error/go.mod index e6a06fc..ddea16f 100644 --- a/_examples/custom_validation_error/go.mod +++ b/_examples/custom_validation_error/go.mod @@ -1,31 +1,34 @@ module custom_validation_error_example -go 1.25.1 +go 1.26.0 -replace github.com/labbs/fiber-oapi => ../.. +replace github.com/labbs/fiber-oapi/v3 => ../.. require ( - github.com/gofiber/fiber/v2 v2.52.12 - github.com/labbs/fiber-oapi v0.0.0-00010101000000-000000000000 + github.com/gofiber/fiber/v3 v3.3.0 + github.com/labbs/fiber-oapi/v3 v3.0.0-00010101000000-000000000000 ) require ( - github.com/andybalholm/brotli v1.2.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.12 // indirect + github.com/andybalholm/brotli v1.2.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.13 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.30.1 // indirect + github.com/go-playground/validator/v10 v10.30.2 // indirect + github.com/gofiber/schema v1.7.1 // indirect + github.com/gofiber/utils/v2 v2.0.6 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.17 // indirect - github.com/rivo/uniseg v0.4.7 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/philhofer/fwd v1.2.0 // indirect + github.com/tinylib/msgp v1.6.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.66.0 // indirect - golang.org/x/crypto v0.46.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.32.0 // indirect + github.com/valyala/fasthttp v1.71.0 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.54.0 // indirect + golang.org/x/sys v0.44.0 // indirect + golang.org/x/text v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/_examples/custom_validation_error/go.sum b/_examples/custom_validation_error/go.sum index 432c529..f2ae6bb 100644 --- a/_examples/custom_validation_error/go.sum +++ b/_examples/custom_validation_error/go.sum @@ -1,51 +1,61 @@ -github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= -github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro= +github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= -github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78= +github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= +github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= -github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= -github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= -github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ= +github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc= +github.com/gofiber/fiber/v3 v3.3.0 h1:QBd3sYCqdy6Qs5gJYzSw4I4SbqL204jPqpdub/ueiw8= +github.com/gofiber/fiber/v3 v3.3.0/go.mod h1:YH7/TAoRaU4kF8slDCtQuFJ1NzC+3MtxUI4KfvQtaIA= +github.com/gofiber/schema v1.7.1 h1:oSJBKdgP8JeIME4TQSAqlNKTU2iBB+2RNmKi8Nsc+TI= +github.com/gofiber/schema v1.7.1/go.mod h1:A/X5Ffyru4p9eBdp99qu+nzviHzQiZ7odLT+TwxWhbk= +github.com/gofiber/utils/v2 v2.0.6 h1:7fXYy7nSsyqbH0GQUMtK4Kwjy4J7R5742VM7JsZxzOs= +github.com/gofiber/utils/v2 v2.0.6/go.mod h1:p7mAHAk3+oUK10ZX2xTw9fZQixb4hCg8SKd4IH2xroU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.17 h1:78v8ZlW0bP43XfmAfPsdXcoNCelfMHsDmd/pkENfrjQ= -github.com/mattn/go-runewidth v0.0.17/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= +github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/shamaton/msgpack/v3 v3.1.2 h1:d5gWAIyMU4M0WgDjz6IFSCuXJUA2dFwRHBpDclE8CLw= +github.com/shamaton/msgpack/v3 v3.1.2/go.mod h1:DcQG8jrdrQCIxr3HlMYkiXdMhK+KfN2CitkyzsQV4uc= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ= +github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.66.0 h1:M87A0Z7EayeyNaV6pfO3tUTUiYO0dZfEJnRGXTVNuyU= -github.com/valyala/fasthttp v1.66.0/go.mod h1:Y4eC+zwoocmXSVCB1JmhNbYtS7tZPRI2ztPB72EVObs= +github.com/valyala/fasthttp v1.71.0 h1:tepR7H+Guh9VUqxxcPggYi8R3lGUu2Rsdh+z7/FCY3k= +github.com/valyala/fasthttp v1.71.0/go.mod h1:z1sDUvOShhXq/C9mwH/fSm1Vb71tUJwmQdgkBrBNwnA= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/_examples/custom_validation_error/main.go b/_examples/custom_validation_error/main.go index 7c2ff56..ddc54f8 100644 --- a/_examples/custom_validation_error/main.go +++ b/_examples/custom_validation_error/main.go @@ -3,8 +3,8 @@ package main import ( "log" - "github.com/gofiber/fiber/v2" - fiberoapi "github.com/labbs/fiber-oapi" + "github.com/gofiber/fiber/v3" + fiberoapi "github.com/labbs/fiber-oapi/v3" ) // CustomErrorResponse is the structure for custom validation error responses @@ -38,7 +38,7 @@ func main() { EnableValidation: true, EnableOpenAPIDocs: true, // Define your custom handler for validation errors - ValidationErrorHandler: func(c *fiber.Ctx, err error) error { + ValidationErrorHandler: func(c fiber.Ctx, err error) error { // You can parse the validation error to extract more details // or simply return your custom structure return c.Status(fiber.StatusBadRequest).JSON(CustomErrorResponse{ @@ -53,7 +53,7 @@ func main() { fiberoapi.Post[CreateUserInput, CreateUserOutput, struct{}]( oapi, "/users", - func(c *fiber.Ctx, input CreateUserInput) (CreateUserOutput, struct{}) { + func(c fiber.Ctx, input CreateUserInput) (CreateUserOutput, struct{}) { // User creation logic goes here return CreateUserOutput{ ID: 1, diff --git a/_examples/simple/go.mod b/_examples/simple/go.mod index 7b12e39..484e72c 100644 --- a/_examples/simple/go.mod +++ b/_examples/simple/go.mod @@ -1,31 +1,34 @@ module simple -go 1.24.2 +go 1.26.0 -replace github.com/labbs/fiber-oapi => ../.. +replace github.com/labbs/fiber-oapi/v3 => ../.. require ( - github.com/gofiber/fiber/v2 v2.52.12 - github.com/labbs/fiber-oapi v0.0.0-00010101000000-000000000000 + github.com/gofiber/fiber/v3 v3.3.0 + github.com/labbs/fiber-oapi/v3 v3.0.0-00010101000000-000000000000 ) require ( - github.com/andybalholm/brotli v1.2.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.12 // indirect + github.com/andybalholm/brotli v1.2.1 // indirect + github.com/gabriel-vasile/mimetype v1.4.13 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.30.1 // indirect + github.com/go-playground/validator/v10 v10.30.2 // indirect + github.com/gofiber/schema v1.7.1 // indirect + github.com/gofiber/utils/v2 v2.0.6 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.17 // indirect - github.com/rivo/uniseg v0.4.7 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/philhofer/fwd v1.2.0 // indirect + github.com/tinylib/msgp v1.6.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.66.0 // indirect - golang.org/x/crypto v0.46.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.32.0 // indirect + github.com/valyala/fasthttp v1.71.0 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.54.0 // indirect + golang.org/x/sys v0.44.0 // indirect + golang.org/x/text v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/_examples/simple/go.sum b/_examples/simple/go.sum index 432c529..f2ae6bb 100644 --- a/_examples/simple/go.sum +++ b/_examples/simple/go.sum @@ -1,51 +1,61 @@ -github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= -github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro= +github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= -github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78= +github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= +github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= -github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= -github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= -github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ= +github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc= +github.com/gofiber/fiber/v3 v3.3.0 h1:QBd3sYCqdy6Qs5gJYzSw4I4SbqL204jPqpdub/ueiw8= +github.com/gofiber/fiber/v3 v3.3.0/go.mod h1:YH7/TAoRaU4kF8slDCtQuFJ1NzC+3MtxUI4KfvQtaIA= +github.com/gofiber/schema v1.7.1 h1:oSJBKdgP8JeIME4TQSAqlNKTU2iBB+2RNmKi8Nsc+TI= +github.com/gofiber/schema v1.7.1/go.mod h1:A/X5Ffyru4p9eBdp99qu+nzviHzQiZ7odLT+TwxWhbk= +github.com/gofiber/utils/v2 v2.0.6 h1:7fXYy7nSsyqbH0GQUMtK4Kwjy4J7R5742VM7JsZxzOs= +github.com/gofiber/utils/v2 v2.0.6/go.mod h1:p7mAHAk3+oUK10ZX2xTw9fZQixb4hCg8SKd4IH2xroU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.17 h1:78v8ZlW0bP43XfmAfPsdXcoNCelfMHsDmd/pkENfrjQ= -github.com/mattn/go-runewidth v0.0.17/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= +github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/shamaton/msgpack/v3 v3.1.2 h1:d5gWAIyMU4M0WgDjz6IFSCuXJUA2dFwRHBpDclE8CLw= +github.com/shamaton/msgpack/v3 v3.1.2/go.mod h1:DcQG8jrdrQCIxr3HlMYkiXdMhK+KfN2CitkyzsQV4uc= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ= +github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.66.0 h1:M87A0Z7EayeyNaV6pfO3tUTUiYO0dZfEJnRGXTVNuyU= -github.com/valyala/fasthttp v1.66.0/go.mod h1:Y4eC+zwoocmXSVCB1JmhNbYtS7tZPRI2ztPB72EVObs= +github.com/valyala/fasthttp v1.71.0 h1:tepR7H+Guh9VUqxxcPggYi8R3lGUu2Rsdh+z7/FCY3k= +github.com/valyala/fasthttp v1.71.0/go.mod h1:z1sDUvOShhXq/C9mwH/fSm1Vb71tUJwmQdgkBrBNwnA= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/_examples/simple/main.go b/_examples/simple/main.go index f69621b..2c12530 100644 --- a/_examples/simple/main.go +++ b/_examples/simple/main.go @@ -3,8 +3,8 @@ package main import ( "fmt" - "github.com/gofiber/fiber/v2" - fiberoapi "github.com/labbs/fiber-oapi" + "github.com/gofiber/fiber/v3" + fiberoapi "github.com/labbs/fiber-oapi/v3" ) type ContextRequest struct { @@ -97,7 +97,7 @@ func main() { // appOApi := fiberoapi.New(app) // Will use defaults: /docs and /openapi.json // Route GET avec validation (path + header parameters) - fiberoapi.Get(appOApi, "/greeting/:name", func(c *fiber.Ctx, input GetInput) (GetOutput, GetError) { + fiberoapi.Get(appOApi, "/greeting/:name", func(c fiber.Ctx, input GetInput) (GetOutput, GetError) { name := input.Name return GetOutput{Message: fmt.Sprintf("Hello %s (request: %s)", name, input.RequestID)}, GetError{} }, fiberoapi.OpenAPIOptions{ @@ -108,7 +108,7 @@ func main() { }) // POST route with complex validation - fiberoapi.Post(appOApi, "/users", func(c *fiber.Ctx, input CreateUserInput) (CreateUserOutput, CreateUserError) { + fiberoapi.Post(appOApi, "/users", func(c fiber.Ctx, input CreateUserInput) (CreateUserOutput, CreateUserError) { // Simulate user creation if input.Username == "admin" { return CreateUserOutput{}, CreateUserError{ @@ -133,7 +133,7 @@ func main() { }) // PUT route for updating user - fiberoapi.Put(appOApi, "/users/:id", func(c *fiber.Ctx, input UpdateUserInput) (UpdateUserOutput, CreateUserError) { + fiberoapi.Put(appOApi, "/users/:id", func(c fiber.Ctx, input UpdateUserInput) (UpdateUserOutput, CreateUserError) { // Simulate user update if input.ID == "nonexistent" { return UpdateUserOutput{}, CreateUserError{ @@ -159,7 +159,7 @@ func main() { }) // DELETE route for removing user - fiberoapi.Delete(appOApi, "/users/:id", func(c *fiber.Ctx, input DeleteUserInput) (DeleteUserOutput, CreateUserError) { + fiberoapi.Delete(appOApi, "/users/:id", func(c fiber.Ctx, input DeleteUserInput) (DeleteUserOutput, CreateUserError) { // Simulate user deletion if input.ID == "protected" { return DeleteUserOutput{}, CreateUserError{ @@ -183,7 +183,7 @@ func main() { }) // GET route with group - fiberoapi.Get(v1, "/greeting/:name", func(c *fiber.Ctx, input GetInput) (GetOutput, GetError) { + fiberoapi.Get(v1, "/greeting/:name", func(c fiber.Ctx, input GetInput) (GetOutput, GetError) { name := input.Name return GetOutput{Message: "Hello " + name}, GetError{} }, fiberoapi.OpenAPIOptions{ diff --git a/auth.go b/auth.go index 32ae888..f8a9423 100644 --- a/auth.go +++ b/auth.go @@ -6,7 +6,7 @@ import ( "reflect" "strings" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // AuthContext contains user authentication details @@ -50,7 +50,7 @@ type SecurityScheme struct { } // GetAuthContext extracts the authentication context from Fiber -func GetAuthContext(c *fiber.Ctx) (*AuthContext, error) { +func GetAuthContext(c fiber.Ctx) (*AuthContext, error) { auth, ok := c.Locals("auth").(*AuthContext) if !ok { return nil, fmt.Errorf("no authentication context found") @@ -59,7 +59,7 @@ func GetAuthContext(c *fiber.Ctx) (*AuthContext, error) { } // RequireResourceAccess checks permissions in handlers -func RequireResourceAccess(c *fiber.Ctx, authService AuthorizationService, resourceType, resourceID, action string) error { +func RequireResourceAccess(c fiber.Ctx, authService AuthorizationService, resourceType, resourceID, action string) error { authCtx, err := GetAuthContext(c) if err != nil { return c.Status(401).JSON(fiber.Map{ @@ -88,7 +88,7 @@ func RequireResourceAccess(c *fiber.Ctx, authService AuthorizationService, resou // BearerTokenMiddleware creates a JWT/Bearer middleware func BearerTokenMiddleware(validator AuthorizationService) fiber.Handler { - return func(c *fiber.Ctx) error { + return func(c fiber.Ctx) error { authHeader := c.Get("Authorization") if authHeader == "" { return c.Status(401).JSON(fiber.Map{ @@ -119,7 +119,7 @@ func BearerTokenMiddleware(validator AuthorizationService) fiber.Handler { // RoleGuard middleware for role verification func RoleGuard(validator AuthorizationService, requiredRoles ...string) fiber.Handler { - return func(c *fiber.Ctx) error { + return func(c fiber.Ctx) error { authCtx, err := GetAuthContext(c) if err != nil { return c.Status(401).JSON(fiber.Map{ @@ -142,7 +142,7 @@ func RoleGuard(validator AuthorizationService, requiredRoles ...string) fiber.Ha // validateAuthorization validates permissions based on configured security schemes. // When SecuritySchemes is empty, it falls back to Bearer-only validation for backward compatibility. -func validateAuthorization(c *fiber.Ctx, input interface{}, authService AuthorizationService, config *Config, requiredRoles []string, requireAllRoles bool) error { +func validateAuthorization(c fiber.Ctx, input interface{}, authService AuthorizationService, config *Config, requiredRoles []string, requireAllRoles bool) error { if authService == nil { if len(requiredRoles) > 0 { return &AuthError{StatusCode: 500, Message: "authorization service not configured"} @@ -240,7 +240,7 @@ func checkRequiredRoles(authCtx *AuthContext, authService AuthorizationService, } // validateResourceAccess validates resource access based on tags -func validateResourceAccess(c *fiber.Ctx, authCtx *AuthContext, input interface{}, authService AuthorizationService) error { +func validateResourceAccess(c fiber.Ctx, authCtx *AuthContext, input interface{}, authService AuthorizationService) error { inputValue := reflect.ValueOf(input) inputType := reflect.TypeOf(input) diff --git a/auth_middleware_test.go b/auth_middleware_test.go index abca898..1dfda4c 100644 --- a/auth_middleware_test.go +++ b/auth_middleware_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) func TestBearerTokenMiddleware(t *testing.T) { @@ -15,7 +15,7 @@ func TestBearerTokenMiddleware(t *testing.T) { t.Run("Valid token sets auth context", func(t *testing.T) { app := fiber.New() app.Use(middleware) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { authCtx, err := GetAuthContext(c) if err != nil { return c.Status(500).JSON(fiber.Map{"error": err.Error()}) @@ -42,7 +42,7 @@ func TestBearerTokenMiddleware(t *testing.T) { t.Run("Invalid token returns error", func(t *testing.T) { app := fiber.New() app.Use(middleware) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -62,7 +62,7 @@ func TestBearerTokenMiddleware(t *testing.T) { t.Run("Missing authorization header returns error", func(t *testing.T) { app := fiber.New() app.Use(middleware) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -88,13 +88,13 @@ func TestConditionalAuthMiddleware(t *testing.T) { app := fiber.New() app.Use(conditionalMiddleware) - app.Get("/docs", func(c *fiber.Ctx) error { + app.Get("/docs", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "docs page"}) }) - app.Get("/health", func(c *fiber.Ctx) error { + app.Get("/health", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"status": "ok"}) }) - app.Get("/protected", func(c *fiber.Ctx) error { + app.Get("/protected", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "protected"}) }) diff --git a/auth_schemes.go b/auth_schemes.go index f1baa85..5467a14 100644 --- a/auth_schemes.go +++ b/auth_schemes.go @@ -6,7 +6,7 @@ import ( "sort" "strings" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // BasicAuthValidator is an optional interface for services that support @@ -56,7 +56,7 @@ type AWSSignatureParams struct { } // validateBearerToken validates a Bearer token from the Authorization header. -func validateBearerToken(c *fiber.Ctx, authService AuthorizationService) (*AuthContext, error) { +func validateBearerToken(c fiber.Ctx, authService AuthorizationService) (*AuthContext, error) { authHeader := c.Get("Authorization") if authHeader == "" { return nil, fmt.Errorf("authentication required: Bearer token expected") @@ -71,7 +71,7 @@ func validateBearerToken(c *fiber.Ctx, authService AuthorizationService) (*AuthC } // validateBasicAuth validates Basic Auth credentials from the Authorization header. -func validateBasicAuth(c *fiber.Ctx, authService AuthorizationService) (*AuthContext, error) { +func validateBasicAuth(c fiber.Ctx, authService AuthorizationService) (*AuthContext, error) { basicValidator, ok := authService.(BasicAuthValidator) if !ok { return nil, &AuthError{StatusCode: 500, Message: "Basic Auth scheme configured but AuthService does not implement BasicAuthValidator"} @@ -101,7 +101,7 @@ func validateBasicAuth(c *fiber.Ctx, authService AuthorizationService) (*AuthCon } // validateAPIKey validates an API key from header, query, or cookie. -func validateAPIKey(c *fiber.Ctx, scheme SecurityScheme, authService AuthorizationService) (*AuthContext, error) { +func validateAPIKey(c fiber.Ctx, scheme SecurityScheme, authService AuthorizationService) (*AuthContext, error) { apiKeyValidator, ok := authService.(APIKeyValidator) if !ok { return nil, &AuthError{StatusCode: 500, Message: "API Key scheme configured but AuthService does not implement APIKeyValidator"} @@ -127,7 +127,7 @@ func validateAPIKey(c *fiber.Ctx, scheme SecurityScheme, authService Authorizati } // validateAWSSigV4 validates an AWS Signature V4 Authorization header. -func validateAWSSigV4(c *fiber.Ctx, authService AuthorizationService) (*AuthContext, error) { +func validateAWSSigV4(c fiber.Ctx, authService AuthorizationService) (*AuthContext, error) { awsValidator, ok := authService.(AWSSignatureValidator) if !ok { return nil, &AuthError{StatusCode: 500, Message: "AWS SigV4 scheme configured but AuthService does not implement AWSSignatureValidator"} @@ -202,7 +202,7 @@ func parseAWSSigV4Header(header string) (*AWSSignatureParams, error) { } // validateWithScheme dispatches validation to the appropriate scheme handler. -func validateWithScheme(c *fiber.Ctx, scheme SecurityScheme, authService AuthorizationService) (*AuthContext, error) { +func validateWithScheme(c fiber.Ctx, scheme SecurityScheme, authService AuthorizationService) (*AuthContext, error) { switch { case scheme.Type == "http" && strings.EqualFold(scheme.Scheme, "bearer"): return validateBearerToken(c, authService) @@ -241,7 +241,7 @@ func (e *ScopeError) Error() string { // ALL schemes in a requirement must validate (AND semantics). // When multiple schemes are present, their AuthContexts are merged: UserIDs must // match (or be empty), and roles/scopes/claims are combined. -func validateSecurityRequirement(c *fiber.Ctx, requirement map[string][]string, schemes map[string]SecurityScheme, authService AuthorizationService) (*AuthContext, error) { +func validateSecurityRequirement(c fiber.Ctx, requirement map[string][]string, schemes map[string]SecurityScheme, authService AuthorizationService) (*AuthContext, error) { if len(requirement) == 0 { return nil, &AuthError{StatusCode: 500, Message: "empty security requirement"} } diff --git a/auth_schemes_test.go b/auth_schemes_test.go index 103b14e..d1a8790 100644 --- a/auth_schemes_test.go +++ b/auth_schemes_test.go @@ -8,7 +8,7 @@ import ( "net/http/httptest" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // --- Mock services --- @@ -149,7 +149,7 @@ func TestValidateBasicAuth_ValidCredentials(t *testing.T) { app := fiber.New() authService := NewMockBasicAuthService() app.Use(BasicAuthMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { authCtx, _ := GetAuthContext(c) return c.JSON(fiber.Map{"user_id": authCtx.UserID}) }) @@ -170,7 +170,7 @@ func TestValidateBasicAuth_InvalidCredentials(t *testing.T) { app := fiber.New() authService := NewMockBasicAuthService() app.Use(BasicAuthMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -190,7 +190,7 @@ func TestValidateBasicAuth_MalformedBase64(t *testing.T) { app := fiber.New() authService := NewMockBasicAuthService() app.Use(BasicAuthMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -209,7 +209,7 @@ func TestValidateBasicAuth_MissingColon(t *testing.T) { app := fiber.New() authService := NewMockBasicAuthService() app.Use(BasicAuthMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -229,7 +229,7 @@ func TestValidateBasicAuth_MissingHeader(t *testing.T) { app := fiber.New() authService := NewMockBasicAuthService() app.Use(BasicAuthMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -248,7 +248,7 @@ func TestValidateBasicAuth_ServiceDoesNotImplement(t *testing.T) { // Use plain MockAuthService which does NOT implement BasicAuthValidator authService := NewMockAuthService() app.Use(BasicAuthMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -271,7 +271,7 @@ func TestValidateAPIKey_InHeader_Valid(t *testing.T) { authService := NewMockAPIKeyAuthService() scheme := SecurityScheme{Type: "apiKey", In: "header", Name: "X-API-Key"} app.Use(APIKeyMiddleware(authService, scheme)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { authCtx, _ := GetAuthContext(c) return c.JSON(fiber.Map{"user_id": authCtx.UserID}) }) @@ -292,7 +292,7 @@ func TestValidateAPIKey_InQuery_Valid(t *testing.T) { authService := NewMockAPIKeyAuthService() scheme := SecurityScheme{Type: "apiKey", In: "query", Name: "api_key"} app.Use(APIKeyMiddleware(authService, scheme)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { authCtx, _ := GetAuthContext(c) return c.JSON(fiber.Map{"user_id": authCtx.UserID}) }) @@ -312,7 +312,7 @@ func TestValidateAPIKey_InCookie_Valid(t *testing.T) { authService := NewMockAPIKeyAuthService() scheme := SecurityScheme{Type: "apiKey", In: "cookie", Name: "api_key"} app.Use(APIKeyMiddleware(authService, scheme)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { authCtx, _ := GetAuthContext(c) return c.JSON(fiber.Map{"user_id": authCtx.UserID}) }) @@ -333,7 +333,7 @@ func TestValidateAPIKey_Missing(t *testing.T) { authService := NewMockAPIKeyAuthService() scheme := SecurityScheme{Type: "apiKey", In: "header", Name: "X-API-Key"} app.Use(APIKeyMiddleware(authService, scheme)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -352,7 +352,7 @@ func TestValidateAPIKey_Invalid(t *testing.T) { authService := NewMockAPIKeyAuthService() scheme := SecurityScheme{Type: "apiKey", In: "header", Name: "X-API-Key"} app.Use(APIKeyMiddleware(authService, scheme)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -372,7 +372,7 @@ func TestValidateAPIKey_ServiceDoesNotImplement(t *testing.T) { authService := NewMockAuthService() scheme := SecurityScheme{Type: "apiKey", In: "header", Name: "X-API-Key"} app.Use(APIKeyMiddleware(authService, scheme)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -393,7 +393,7 @@ func TestValidateAWSSigV4_ValidSignature(t *testing.T) { app := fiber.New() authService := NewMockAWSAuthService() app.Use(AWSSignatureMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { authCtx, _ := GetAuthContext(c) return c.JSON(fiber.Map{"user_id": authCtx.UserID}) }) @@ -415,7 +415,7 @@ func TestValidateAWSSigV4_InvalidAccessKey(t *testing.T) { app := fiber.New() authService := NewMockAWSAuthService() app.Use(AWSSignatureMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -434,7 +434,7 @@ func TestValidateAWSSigV4_MalformedHeader(t *testing.T) { app := fiber.New() authService := NewMockAWSAuthService() app.Use(AWSSignatureMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -453,7 +453,7 @@ func TestValidateAWSSigV4_MissingHeader(t *testing.T) { app := fiber.New() authService := NewMockAWSAuthService() app.Use(AWSSignatureMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -471,7 +471,7 @@ func TestValidateAWSSigV4_ServiceDoesNotImplement(t *testing.T) { app := fiber.New() authService := NewMockAuthService() app.Use(AWSSignatureMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -554,7 +554,7 @@ func TestMultiScheme_BearerStillWorks(t *testing.T) { }, } app.Use(MultiSchemeAuthMiddleware(authService, config)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { authCtx, _ := GetAuthContext(c) return c.JSON(fiber.Map{"user_id": authCtx.UserID}) }) @@ -584,7 +584,7 @@ func TestMultiScheme_FallbackToSecondScheme(t *testing.T) { }, } app.Use(MultiSchemeAuthMiddleware(authService, config)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { authCtx, _ := GetAuthContext(c) return c.JSON(fiber.Map{"user_id": authCtx.UserID}) }) @@ -615,7 +615,7 @@ func TestMultiScheme_AllSchemesFail(t *testing.T) { }, } app.Use(MultiSchemeAuthMiddleware(authService, config)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.JSON(fiber.Map{"message": "should not reach here"}) }) @@ -645,7 +645,7 @@ func TestBackwardCompat_ExistingMockAuthService(t *testing.T) { // No SecuritySchemes configured - should fallback to Bearer-only }) - Get(oapi, "/test", func(c *fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { + Get(oapi, "/test", func(c fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { authCtx, err := GetAuthContext(c) if err != nil { return nil, &ErrorResponse{Code: 500, Details: err.Error()} @@ -669,7 +669,7 @@ func TestBackwardCompat_BearerTokenMiddleware(t *testing.T) { app := fiber.New() authService := NewMockAuthService() app.Use(BearerTokenMiddleware(authService)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { authCtx, _ := GetAuthContext(c) return c.JSON(fiber.Map{"user_id": authCtx.UserID}) }) @@ -703,11 +703,11 @@ func TestSmartAuthMiddleware_WithSecuritySchemes(t *testing.T) { }, } app.Use(SmartAuthMiddleware(authService, config)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { authCtx, _ := GetAuthContext(c) return c.JSON(fiber.Map{"user_id": authCtx.UserID}) }) - app.Get("/docs", func(c *fiber.Ctx) error { + app.Get("/docs", func(c fiber.Ctx) error { return c.SendString("docs") }) @@ -750,7 +750,7 @@ func TestValidateSecurityRequirement_ANDMergesContexts(t *testing.T) { "apiKey": {}, } - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { authCtx, err := validateSecurityRequirement(c, requirement, schemes, authService) if err != nil { return c.Status(401).JSON(fiber.Map{"error": err.Error()}) @@ -841,7 +841,7 @@ func TestValidateSecurityRequirement_ANDConflictingUserID(t *testing.T) { "apiKey": {}, } - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { _, err := validateSecurityRequirement(c, requirement, schemes, authService) if err != nil { return c.Status(401).JSON(fiber.Map{"error": err.Error()}) @@ -875,7 +875,7 @@ func TestValidateAPIKey_UnsupportedLocation(t *testing.T) { }, } app.Use(MultiSchemeAuthMiddleware(authService, config)) - app.Get("/test", func(c *fiber.Ctx) error { + app.Get("/test", func(c fiber.Ctx) error { return c.SendStatus(200) }) @@ -913,7 +913,7 @@ func TestPerRouteSecurity_OverridesGlobalDefault(t *testing.T) { routeSecurity := []map[string][]string{ {"apiKey": {}}, } - Get(oapi, "/api-key-route", func(c *fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { + Get(oapi, "/api-key-route", func(c fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { authCtx, err := GetAuthContext(c) if err != nil { return nil, &ErrorResponse{Code: 500, Details: err.Error()} @@ -957,7 +957,7 @@ func TestSecurityScheme_YAMLSpec_CorrectKeys(t *testing.T) { }) // Register a dummy route so the spec is non-empty - Get(oapi, "/ping", func(c *fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { + Get(oapi, "/ping", func(c fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { return fiber.Map{"ok": true}, nil }, OpenAPIOptions{Summary: "Ping"}) diff --git a/auth_test.go b/auth_test.go index 7e2432c..48326bd 100644 --- a/auth_test.go +++ b/auth_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // Mock AuthorizationService for testing @@ -177,7 +177,7 @@ func TestAuthenticationMiddleware(t *testing.T) { t.Run("Public endpoint without auth", func(t *testing.T) { Get(oapi, "/public", - func(c *fiber.Ctx, input struct{}) (TestResponse, *ErrorResponse) { + func(c fiber.Ctx, input struct{}) (TestResponse, *ErrorResponse) { return TestResponse{ ID: "public", Message: "This is public", @@ -202,7 +202,7 @@ func TestAuthenticationMiddleware(t *testing.T) { t.Run("Protected endpoint without token", func(t *testing.T) { Get(oapi, "/protected", - func(c *fiber.Ctx, input struct{}) (TestResponse, *ErrorResponse) { + func(c fiber.Ctx, input struct{}) (TestResponse, *ErrorResponse) { return TestResponse{ ID: "protected", Message: "This is protected", @@ -226,7 +226,7 @@ func TestAuthenticationMiddleware(t *testing.T) { t.Run("Protected endpoint with valid token", func(t *testing.T) { Get(oapi, "/user-info", - func(c *fiber.Ctx, input struct{}) (TestResponse, *ErrorResponse) { + func(c fiber.Ctx, input struct{}) (TestResponse, *ErrorResponse) { authCtx, _ := GetAuthContext(c) return TestResponse{ ID: authCtx.UserID, @@ -300,7 +300,7 @@ func TestRoleBasedAccess(t *testing.T) { // Endpoint requiring admin role Delete(oapi, "/admin/:id", - func(c *fiber.Ctx, input TestRequest) (TestResponse, *ErrorResponse) { + func(c fiber.Ctx, input TestRequest) (TestResponse, *ErrorResponse) { authCtx, _ := GetAuthContext(c) // Check admin role manually in handler @@ -364,7 +364,7 @@ func TestScopeBasedAccess(t *testing.T) { // Endpoint requiring write scope Put(oapi, "/documents/:id", - func(c *fiber.Ctx, input struct { + func(c fiber.Ctx, input struct { ID string `path:"id" validate:"required"` Name string `json:"name" validate:"required"` }) (TestResponse, *ErrorResponse) { @@ -437,7 +437,7 @@ func TestPOSTWithoutBody(t *testing.T) { // POST endpoint without body (like share) Post(oapi, "/documents/:id/share", - func(c *fiber.Ctx, input TestRequest) (TestResponse, *ErrorResponse) { + func(c fiber.Ctx, input TestRequest) (TestResponse, *ErrorResponse) { authCtx, _ := GetAuthContext(c) return TestResponse{ @@ -488,7 +488,7 @@ func TestGetAuthContext(t *testing.T) { oapi := New(app, config) Get(oapi, "/context-test", - func(c *fiber.Ctx, input struct{}) (map[string]interface{}, *ErrorResponse) { + func(c fiber.Ctx, input struct{}) (map[string]interface{}, *ErrorResponse) { authCtx, err := GetAuthContext(c) if err != nil { return nil, &ErrorResponse{ @@ -549,7 +549,7 @@ func TestAuthServiceFailure(t *testing.T) { oapi := New(app, config) Get(oapi, "/fail-test", - func(c *fiber.Ctx, input struct{}) (TestResponse, *ErrorResponse) { + func(c fiber.Ctx, input struct{}) (TestResponse, *ErrorResponse) { return TestResponse{ ID: "test", Message: "Should not reach here", @@ -593,22 +593,22 @@ func TestRequiredRoles(t *testing.T) { }) // Route requiring "admin" role - Get(oapi, "/admin/users", func(c *fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { + Get(oapi, "/admin/users", func(c fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { return fiber.Map{"ok": true}, nil }, WithRoles(OpenAPIOptions{Summary: "Admin only"}, "admin")) // Route requiring "user" role (both tokens have this) - Get(oapi, "/user/profile", func(c *fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { + Get(oapi, "/user/profile", func(c fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { return fiber.Map{"ok": true}, nil }, WithRoles(OpenAPIOptions{Summary: "User profile"}, "user")) // Route requiring multiple roles (OR semantics): "admin" OR "editor" - Get(oapi, "/admin/settings", func(c *fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { + Get(oapi, "/admin/settings", func(c fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { return fiber.Map{"ok": true}, nil }, WithRoles(OpenAPIOptions{Summary: "Admin settings"}, "admin", "editor")) // Route with no required roles - Get(oapi, "/public/info", func(c *fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { + Get(oapi, "/public/info", func(c fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { return fiber.Map{"ok": true}, nil }, OpenAPIOptions{Summary: "Public info"}) @@ -742,7 +742,7 @@ func TestCustomAuthErrorHandler(t *testing.T) { DefaultSecurity: []map[string][]string{ {"bearerAuth": {}}, }, - AuthErrorHandler: func(c *fiber.Ctx, err *AuthError) error { + AuthErrorHandler: func(c fiber.Ctx, err *AuthError) error { return c.Status(err.StatusCode).JSON(fiber.Map{ "custom": true, "message": err.Message, @@ -751,7 +751,7 @@ func TestCustomAuthErrorHandler(t *testing.T) { }, }) - Get(oapi, "/protected", func(c *fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { + Get(oapi, "/protected", func(c fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { return fiber.Map{"ok": true}, nil }, OpenAPIOptions{Summary: "Protected"}) @@ -771,7 +771,7 @@ func TestCustomAuthErrorHandler(t *testing.T) { }) t.Run("custom handler for 403", func(t *testing.T) { - Get(oapi, "/admin-only", func(c *fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { + Get(oapi, "/admin-only", func(c fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { return fiber.Map{"ok": true}, nil }, WithRoles(OpenAPIOptions{Summary: "Admin only"}, "admin")) @@ -843,7 +843,7 @@ func TestRequiredRoles_ANDSemantics(t *testing.T) { }) // Route requiring ALL of "admin" AND "user" (AND semantics) - Get(oapi, "/strict", func(c *fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { + Get(oapi, "/strict", func(c fiber.Ctx, input struct{}) (fiber.Map, *ErrorResponse) { return fiber.Map{"ok": true}, nil }, WithAllRoles(OpenAPIOptions{Summary: "Strict route"}, "admin", "user")) diff --git a/auto_params_edge_cases_test.go b/auto_params_edge_cases_test.go index eb551ec..4f593a3 100644 --- a/auto_params_edge_cases_test.go +++ b/auto_params_edge_cases_test.go @@ -3,7 +3,7 @@ package fiberoapi import ( "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/stretchr/testify/assert" ) @@ -23,7 +23,7 @@ func TestAutoParamsEdgeCases(t *testing.T) { Code int `json:"code"` } - Get(oapi, "/empty", func(c *fiber.Ctx, input EmptyInput) (EmptyOutput, EmptyError) { + Get(oapi, "/empty", func(c fiber.Ctx, input EmptyInput) (EmptyOutput, EmptyError) { return EmptyOutput{Message: "empty"}, EmptyError{} }, OpenAPIOptions{ OperationID: "emptyTest", @@ -53,7 +53,7 @@ func TestAutoParamsEdgeCases(t *testing.T) { Code int `json:"code"` } - Get(oapi, "/unexported/:public", func(c *fiber.Ctx, input UnexportedFieldsInput) (UnexportedOutput, UnexportedError) { + Get(oapi, "/unexported/:public", func(c fiber.Ctx, input UnexportedFieldsInput) (UnexportedOutput, UnexportedError) { return UnexportedOutput{Message: input.PublicField}, UnexportedError{} }, OpenAPIOptions{ OperationID: "unexportedTest", @@ -86,7 +86,7 @@ func TestAutoParamsEdgeCases(t *testing.T) { Code int `json:"code"` } - Get(oapi, "/both/:field", func(c *fiber.Ctx, input BothTagsInput) (BothTagsOutput, BothTagsError) { + Get(oapi, "/both/:field", func(c fiber.Ctx, input BothTagsInput) (BothTagsOutput, BothTagsError) { return BothTagsOutput{Message: input.Field}, BothTagsError{} }, OpenAPIOptions{ OperationID: "bothTagsTest", @@ -149,7 +149,7 @@ func TestAutoParamsEdgeCases(t *testing.T) { Code int `json:"code"` } - Get(oapi, "/complex", func(c *fiber.Ctx, input ComplexValidationInput) (ComplexValidationOutput, ComplexValidationError) { + Get(oapi, "/complex", func(c fiber.Ctx, input ComplexValidationInput) (ComplexValidationOutput, ComplexValidationError) { return ComplexValidationOutput{Message: "valid"}, ComplexValidationError{} }, OpenAPIOptions{ OperationID: "complexValidationTest", @@ -190,7 +190,7 @@ func TestAutoParamsEdgeCases(t *testing.T) { Code int `json:"code"` } - Get(oapi, "/pointers", func(c *fiber.Ctx, input PointerInput) (PointerOutput, PointerError) { + Get(oapi, "/pointers", func(c fiber.Ctx, input PointerInput) (PointerOutput, PointerError) { return PointerOutput{Message: "pointer"}, PointerError{} }, OpenAPIOptions{ OperationID: "pointerTest", diff --git a/auto_params_test.go b/auto_params_test.go index 57912a5..e376527 100644 --- a/auto_params_test.go +++ b/auto_params_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -37,7 +37,7 @@ func TestAutoGeneratedParameters(t *testing.T) { oapi := New(app) // Register an endpoint with auto-generated parameters - handler := func(c *fiber.Ctx, input AutoParamsTestInput) (AutoParamsTestOutput, AutoParamsTestError) { + handler := func(c fiber.Ctx, input AutoParamsTestInput) (AutoParamsTestOutput, AutoParamsTestError) { return AutoParamsTestOutput(input), AutoParamsTestError{} } @@ -140,7 +140,7 @@ func TestMergeWithManualParameters(t *testing.T) { Message string `json:"message"` } - handler := func(c *fiber.Ctx, input MergeTestInput) (MergeTestOutput, MergeTestError) { + handler := func(c fiber.Ctx, input MergeTestInput) (MergeTestOutput, MergeTestError) { return MergeTestOutput(input), MergeTestError{} } @@ -219,7 +219,7 @@ func TestNoParametersWhenNoStruct(t *testing.T) { } // Register endpoint without input struct - Get(oapi, "/simple", func(c *fiber.Ctx, input struct{}) (SimpleOutput, SimpleError) { + Get(oapi, "/simple", func(c fiber.Ctx, input struct{}) (SimpleOutput, SimpleError) { return SimpleOutput{Message: "hello"}, SimpleError{} }, OpenAPIOptions{ OperationID: "simpleEndpoint", @@ -256,7 +256,7 @@ func TestAutoParamsPointerTypesInline(t *testing.T) { Code int `json:"code"` } - Get(oapi, "/pointer/:id", func(c *fiber.Ctx, input PointerTestInput) (PointerTestOutput, PointerTestError) { + Get(oapi, "/pointer/:id", func(c fiber.Ctx, input PointerTestInput) (PointerTestOutput, PointerTestError) { return PointerTestOutput{Message: "ok"}, PointerTestError{} }, OpenAPIOptions{ OperationID: "testPointerTypes", diff --git a/common.go b/common.go index 84264c1..3764aa6 100644 --- a/common.go +++ b/common.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/go-playground/validator/v10" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // Global validator instance @@ -20,7 +20,7 @@ func init() { // Function to parse input from the request // parseInput parses the input from the request -func parseInput[TInput any](app *OApiApp, c *fiber.Ctx, path string, options *OpenAPIOptions) (TInput, error) { +func parseInput[TInput any](app *OApiApp, c fiber.Ctx, path string, options *OpenAPIOptions) (TInput, error) { var input TInput // Parse path parameters if needed @@ -44,7 +44,7 @@ func parseInput[TInput any](app *OApiApp, c *fiber.Ctx, path string, options *Op // Parse the body if there's content OR if it's a POST/PUT/PATCH with specified Content-Type if bodyLength > 0 || strings.Contains(contentType, "application/json") || strings.Contains(contentType, "application/x-www-form-urlencoded") { - err = c.BodyParser(&input) + err = c.Bind().Body(&input) if err != nil { // For POST requests without a body, ignore the parsing error if bodyLength == 0 && method == "POST" { @@ -134,7 +134,7 @@ func parseInput[TInput any](app *OApiApp, c *fiber.Ctx, path string, options *Op } // Function to handle custom errors -func handleCustomError(c *fiber.Ctx, customErr interface{}) error { +func handleCustomError(c fiber.Ctx, customErr interface{}) error { // Use reflection to extract error information errValue := reflect.ValueOf(customErr) @@ -173,7 +173,7 @@ func isZero(v interface{}) bool { } // Parse path parameters -func parsePathParams(c *fiber.Ctx, input interface{}) error { +func parsePathParams(c fiber.Ctx, input interface{}) error { inputValue := reflect.ValueOf(input).Elem() inputType := dereferenceType(reflect.TypeOf(input).Elem()) @@ -204,7 +204,7 @@ func parsePathParams(c *fiber.Ctx, input interface{}) error { } // Parse query parameters -func parseQueryParams(c *fiber.Ctx, input interface{}) error { +func parseQueryParams(c fiber.Ctx, input interface{}) error { inputValue := reflect.ValueOf(input).Elem() inputType := dereferenceType(reflect.TypeOf(input).Elem()) @@ -237,7 +237,7 @@ func parseQueryParams(c *fiber.Ctx, input interface{}) error { } // Parse header parameters -func parseHeaderParams(c *fiber.Ctx, input interface{}) error { +func parseHeaderParams(c fiber.Ctx, input interface{}) error { inputValue := reflect.ValueOf(input).Elem() inputType := dereferenceType(reflect.TypeOf(input).Elem()) diff --git a/conditional_auth.go b/conditional_auth.go index 287af21..93c05e2 100644 --- a/conditional_auth.go +++ b/conditional_auth.go @@ -4,12 +4,12 @@ import ( "errors" "strings" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // ConditionalAuthMiddleware creates middleware that applies only to specified routes func ConditionalAuthMiddleware(authMiddleware fiber.Handler, excludePaths ...string) fiber.Handler { - return func(c *fiber.Ctx) error { + return func(c fiber.Ctx) error { path := c.Path() // Verify if the current path is in the exclude list @@ -49,7 +49,7 @@ func SmartAuthMiddleware(authService AuthorizationService, config Config) fiber. // It iterates over DefaultSecurity requirements (OR semantics) and validates // using the appropriate scheme handler. func MultiSchemeAuthMiddleware(authService AuthorizationService, config Config) fiber.Handler { - return func(c *fiber.Ctx) error { + return func(c fiber.Ctx) error { securityReqs := config.DefaultSecurity if len(securityReqs) == 0 { securityReqs = buildDefaultFromSchemes(config.SecuritySchemes) @@ -101,7 +101,7 @@ func MultiSchemeAuthMiddleware(authService AuthorizationService, config Config) // BasicAuthMiddleware creates a standalone middleware for HTTP Basic authentication. // The authService must implement the BasicAuthValidator interface. func BasicAuthMiddleware(validator AuthorizationService) fiber.Handler { - return func(c *fiber.Ctx) error { + return func(c fiber.Ctx) error { authCtx, err := validateBasicAuth(c, validator) if err != nil { status, label := classifyAuthError(err) @@ -119,7 +119,7 @@ func BasicAuthMiddleware(validator AuthorizationService) fiber.Handler { // APIKeyMiddleware creates a standalone middleware for API Key authentication. // The authService must implement the APIKeyValidator interface. func APIKeyMiddleware(validator AuthorizationService, scheme SecurityScheme) fiber.Handler { - return func(c *fiber.Ctx) error { + return func(c fiber.Ctx) error { authCtx, err := validateAPIKey(c, scheme, validator) if err != nil { status, label := classifyAuthError(err) @@ -137,7 +137,7 @@ func APIKeyMiddleware(validator AuthorizationService, scheme SecurityScheme) fib // AWSSignatureMiddleware creates a standalone middleware for AWS Signature V4 authentication. // The authService must implement the AWSSignatureValidator interface. func AWSSignatureMiddleware(validator AuthorizationService) fiber.Handler { - return func(c *fiber.Ctx) error { + return func(c fiber.Ctx) error { authCtx, err := validateAWSSigV4(c, validator) if err != nil { status, label := classifyAuthError(err) diff --git a/config_test.go b/config_test.go index cf11578..20759f6 100644 --- a/config_test.go +++ b/config_test.go @@ -3,7 +3,7 @@ package fiberoapi import ( "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) func TestConfigMerging(t *testing.T) { diff --git a/custom_validation_error_test.go b/custom_validation_error_test.go index e10fd6e..4db06c7 100644 --- a/custom_validation_error_test.go +++ b/custom_validation_error_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/stretchr/testify/assert" ) @@ -25,7 +25,7 @@ func TestCustomValidationErrorHandler(t *testing.T) { oapi := New(app, Config{ EnableValidation: true, EnableOpenAPIDocs: false, - ValidationErrorHandler: func(c *fiber.Ctx, err error) error { + ValidationErrorHandler: func(c fiber.Ctx, err error) error { return c.Status(fiber.StatusBadRequest).JSON(CustomValidationError{ Success: false, Message: err.Error(), @@ -46,7 +46,7 @@ func TestCustomValidationErrorHandler(t *testing.T) { Post[TestInput, TestOutput, struct{}]( oapi, "/test", - func(c *fiber.Ctx, input TestInput) (TestOutput, struct{}) { + func(c fiber.Ctx, input TestInput) (TestOutput, struct{}) { return TestOutput{Message: "success"}, struct{}{} }, OpenAPIOptions{}, @@ -96,7 +96,7 @@ func TestDefaultValidationErrorWhenNoCustomHandler(t *testing.T) { Post[TestInput, TestOutput, struct{}]( oapi, "/test", - func(c *fiber.Ctx, input TestInput) (TestOutput, struct{}) { + func(c fiber.Ctx, input TestInput) (TestOutput, struct{}) { return TestOutput{Message: "success"}, struct{}{} }, OpenAPIOptions{}, @@ -131,7 +131,7 @@ func TestCustomValidationErrorHandlerWithDisabledDocs(t *testing.T) { oapi := New(app, Config{ EnableValidation: true, EnableOpenAPIDocs: false, // This should be respected - ValidationErrorHandler: func(c *fiber.Ctx, err error) error { + ValidationErrorHandler: func(c fiber.Ctx, err error) error { return c.Status(fiber.StatusBadRequest).JSON(CustomValidationError{ Success: false, Message: err.Error(), @@ -151,7 +151,7 @@ func TestCustomValidationErrorHandlerWithDisabledDocs(t *testing.T) { Post[TestInput, TestOutput, struct{}]( oapi, "/test", - func(c *fiber.Ctx, input TestInput) (TestOutput, struct{}) { + func(c fiber.Ctx, input TestInput) (TestOutput, struct{}) { return TestOutput{Message: "success"}, struct{}{} }, OpenAPIOptions{}, @@ -189,7 +189,7 @@ func TestValidationErrorHandlerImpliesValidationEnabled(t *testing.T) { // Configure ONLY ValidationErrorHandler without explicitly setting EnableValidation // This should keep validation enabled by default since it makes sense oapi := New(app, Config{ - ValidationErrorHandler: func(c *fiber.Ctx, err error) error { + ValidationErrorHandler: func(c fiber.Ctx, err error) error { return c.Status(fiber.StatusBadRequest).JSON(CustomValidationError{ Success: false, Message: err.Error(), @@ -209,7 +209,7 @@ func TestValidationErrorHandlerImpliesValidationEnabled(t *testing.T) { Post[TestInput, TestOutput, struct{}]( oapi, "/test", - func(c *fiber.Ctx, input TestInput) (TestOutput, struct{}) { + func(c fiber.Ctx, input TestInput) (TestOutput, struct{}) { return TestOutput{Message: "success"}, struct{}{} }, OpenAPIOptions{}, @@ -262,7 +262,7 @@ func TestAuthErrorHandlerOnlyDoesNotDisableDefaults(t *testing.T) { app := fiber.New() oapi := New(app, Config{ - AuthErrorHandler: func(c *fiber.Ctx, err *AuthError) error { + AuthErrorHandler: func(c fiber.Ctx, err *AuthError) error { return c.Status(err.StatusCode).JSON(fiber.Map{"custom": true}) }, }) @@ -277,7 +277,7 @@ func TestAuthErrorHandlerOnlyDoesNotDisableDefaults(t *testing.T) { Post[TestInput, TestOutput, struct{}]( oapi, "/test", - func(c *fiber.Ctx, input TestInput) (TestOutput, struct{}) { + func(c fiber.Ctx, input TestInput) (TestOutput, struct{}) { return TestOutput{Message: "ok"}, struct{}{} }, OpenAPIOptions{}, diff --git a/delete_test.go b/delete_test.go index 834d473..b9b1edd 100644 --- a/delete_test.go +++ b/delete_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // Test structs pour DELETE @@ -44,7 +44,7 @@ func TestDeleteOApi_SimpleDelete(t *testing.T) { oapi := New(app) // Test with simple DELETE (path param only) - Delete(oapi, "/users/:id", func(c *fiber.Ctx, input DeleteUserInput) (DeleteOutput, DeleteError) { + Delete(oapi, "/users/:id", func(c fiber.Ctx, input DeleteUserInput) (DeleteOutput, DeleteError) { return DeleteOutput{ ID: input.ID, Message: fmt.Sprintf("User %s deleted successfully", input.ID), @@ -84,7 +84,7 @@ func TestDeleteOApi_MultiplePathParams(t *testing.T) { oapi := New(app) // Test with DELETE + multiple path parameters - Delete(oapi, "/categories/:categoryId/products/:productId", func(c *fiber.Ctx, input DeleteProductInput) (DeleteOutput, DeleteError) { + Delete(oapi, "/categories/:categoryId/products/:productId", func(c fiber.Ctx, input DeleteProductInput) (DeleteOutput, DeleteError) { return DeleteOutput{ ID: input.ProductID, Message: fmt.Sprintf("Product %s deleted from category %s", input.ProductID, input.CategoryID), @@ -128,7 +128,7 @@ func TestDeleteOApi_WithQueryParams(t *testing.T) { oapi := New(app) // Test with DELETE + path + query parameters - Delete(oapi, "/users/:id", func(c *fiber.Ctx, input DeleteWithQueryInput) (DeleteOutput, DeleteError) { + Delete(oapi, "/users/:id", func(c fiber.Ctx, input DeleteWithQueryInput) (DeleteOutput, DeleteError) { message := fmt.Sprintf("User %s deleted", input.ID) if input.Force { message += " (forced)" @@ -220,7 +220,7 @@ func TestDeleteOApi_Validation(t *testing.T) { app := fiber.New() oapi := New(app) - Delete(oapi, "/categories/:categoryId/products/:productId", func(c *fiber.Ctx, input DeleteProductInput) (DeleteOutput, DeleteError) { + Delete(oapi, "/categories/:categoryId/products/:productId", func(c fiber.Ctx, input DeleteProductInput) (DeleteOutput, DeleteError) { return DeleteOutput{ ID: input.ProductID, Message: "Product deleted", @@ -231,7 +231,7 @@ func TestDeleteOApi_Validation(t *testing.T) { Summary: "Delete product with validation", }) - Delete(oapi, "/users/:id", func(c *fiber.Ctx, input DeleteWithQueryInput) (DeleteOutput, DeleteError) { + Delete(oapi, "/users/:id", func(c fiber.Ctx, input DeleteWithQueryInput) (DeleteOutput, DeleteError) { return DeleteOutput{ ID: input.ID, Message: "User deleted", @@ -333,7 +333,7 @@ func TestDeleteOApi_ErrorHandling(t *testing.T) { oapi := New(app) // Test with custom error handling - Delete(oapi, "/users/:id", func(c *fiber.Ctx, input DeleteUserInput) (DeleteOutput, DeleteError) { + Delete(oapi, "/users/:id", func(c fiber.Ctx, input DeleteUserInput) (DeleteOutput, DeleteError) { if input.ID == "notfound" { return DeleteOutput{}, DeleteError{ StatusCode: 404, @@ -436,7 +436,7 @@ func TestDeleteOApi_OperationStorage(t *testing.T) { // Check that DELETE operations are properly stored initialCount := len(oapi.operations) - Delete(oapi, "/test/:id", func(c *fiber.Ctx, input DeleteUserInput) (DeleteOutput, DeleteError) { + Delete(oapi, "/test/:id", func(c fiber.Ctx, input DeleteUserInput) (DeleteOutput, DeleteError) { return DeleteOutput{Message: "test", Deleted: true}, DeleteError{} }, OpenAPIOptions{ OperationID: "test-delete-operation", diff --git a/docs.go b/docs.go index 142ab57..fbf204e 100644 --- a/docs.go +++ b/docs.go @@ -4,7 +4,7 @@ import ( "html/template" "strings" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // DocConfig contains configuration for the documentation @@ -37,7 +37,7 @@ func (o *OApiApp) SetupDocs(config ...DocConfig) { } // Serve OpenAPI JSON specification - o.f.Get(cfg.JSONPath, func(c *fiber.Ctx) error { + o.f.Get(cfg.JSONPath, func(c fiber.Ctx) error { spec := o.GenerateOpenAPISpec() // Override info section with config values @@ -52,7 +52,7 @@ func (o *OApiApp) SetupDocs(config ...DocConfig) { }) // Serve Redoc documentation - o.f.Get(cfg.DocsPath, func(c *fiber.Ctx) error { + o.f.Get(cfg.DocsPath, func(c fiber.Ctx) error { // Generate HTML with embedded Redoc html := generateRedocHTML(cfg.JSONPath, cfg.Title) c.Set("Content-Type", "text/html") @@ -60,8 +60,8 @@ func (o *OApiApp) SetupDocs(config ...DocConfig) { }) // Serve additional docs routes (with trailing slash) - o.f.Get(cfg.DocsPath+"/", func(c *fiber.Ctx) error { - return c.Redirect(cfg.DocsPath) + o.f.Get(cfg.DocsPath+"/", func(c fiber.Ctx) error { + return c.Redirect().To(cfg.DocsPath) }) } diff --git a/docs_test.go b/docs_test.go index 97bbcc4..256bf5c 100644 --- a/docs_test.go +++ b/docs_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) func TestSetupDocs_Documentation(t *testing.T) { @@ -53,7 +53,7 @@ func TestSetupDocs_CustomConfig(t *testing.T) { oapi := New(app) // Add a test route - Get(oapi, "/health", func(c *fiber.Ctx, input struct{}) (interface{}, struct{}) { + Get(oapi, "/health", func(c fiber.Ctx, input struct{}) (interface{}, struct{}) { return map[string]string{"status": "ok"}, struct{}{} }, OpenAPIOptions{ OperationID: "health-check", diff --git a/fiberoapi.go b/fiberoapi.go index dfa9e42..da3a1c1 100644 --- a/fiberoapi.go +++ b/fiberoapi.go @@ -8,7 +8,7 @@ import ( "strconv" "strings" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "gopkg.in/yaml.v3" ) @@ -119,14 +119,14 @@ func New(app *fiber.App, config ...Config) *OApiApp { func (o *OApiApp) setupDocsRoutes() { // Serve OpenAPI JSON specification - o.f.Get(o.Config().OpenAPIJSONPath, func(c *fiber.Ctx) error { + o.f.Get(o.Config().OpenAPIJSONPath, func(c fiber.Ctx) error { spec := o.GenerateOpenAPISpec() c.Set("Content-Type", "application/json") return c.JSON(spec) }) // Serve OpenAPI YAML specification - o.f.Get(o.Config().OpenAPIYamlPath, func(c *fiber.Ctx) error { + o.f.Get(o.Config().OpenAPIYamlPath, func(c fiber.Ctx) error { spec, err := o.GenerateOpenAPISpecYAML() if err != nil { return err @@ -136,7 +136,7 @@ func (o *OApiApp) setupDocsRoutes() { }) // Serve Redoc documentation - o.f.Get(o.Config().OpenAPIDocsPath, func(c *fiber.Ctx) error { + o.f.Get(o.Config().OpenAPIDocsPath, func(c fiber.Ctx) error { html := generateRedocHTML(o.Config().OpenAPIJSONPath, "API Documentation") c.Set("Content-Type", "text/html") return c.SendString(html) @@ -144,8 +144,8 @@ func (o *OApiApp) setupDocsRoutes() { // Handle trailing slash redirect if !strings.HasSuffix(o.Config().OpenAPIDocsPath, "/") { - o.f.Get(o.Config().OpenAPIDocsPath+"/", func(c *fiber.Ctx) error { - return c.Redirect(o.Config().OpenAPIDocsPath) + o.f.Get(o.Config().OpenAPIDocsPath+"/", func(c fiber.Ctx) error { + return c.Redirect().To(o.Config().OpenAPIDocsPath) }) } } @@ -921,7 +921,7 @@ func Method[TInput any, TOutput any, TError any]( }) // Wrapper - fiberHandler := func(c *fiber.Ctx) error { + fiberHandler := func(c fiber.Ctx) error { input, err := parseInput[TInput](app, c, fullPath, &options) if err != nil { // Check for authentication/authorization errors first @@ -972,7 +972,7 @@ func Method[TInput any, TOutput any, TError any]( return nil } - app.f.Add(m, fullPath, fiberHandler) + app.f.Add([]string{m}, fullPath, fiberHandler) } // Get defines a GET operation for the OpenAPI documentation diff --git a/get_oapi_test.go b/get_oapi_test.go index 24b4d50..3941631 100644 --- a/get_oapi_test.go +++ b/get_oapi_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // Test structs @@ -52,7 +52,7 @@ func TestGetOApi_SingleParam(t *testing.T) { oapi := New(app) // Test with a single parameter - Get(oapi, "/users/:name", func(c *fiber.Ctx, input SingleParamInput) (TestOutput, TestError) { + Get(oapi, "/users/:name", func(c fiber.Ctx, input SingleParamInput) (TestOutput, TestError) { if input.Name == "" { return TestOutput{}, TestError{StatusCode: 400, Message: "Name is required"} } @@ -83,7 +83,7 @@ func TestGetOApi_MultipleParams(t *testing.T) { oapi := New(app) // Test with multiple parameters - Get(oapi, "/users/:userId/posts/:postId", func(c *fiber.Ctx, input MultiParamInput) (TestOutput, TestError) { + Get(oapi, "/users/:userId/posts/:postId", func(c fiber.Ctx, input MultiParamInput) (TestOutput, TestError) { return TestOutput{ Message: "User " + input.UserID + " post " + input.PostID, Data: map[string]string{ @@ -124,7 +124,7 @@ func TestGetOApi_ParamWithQuery(t *testing.T) { oapi := New(app) // Test with path parameter + query - Get(oapi, "/greeting/:name", func(c *fiber.Ctx, input ParamWithQueryInput) (TestOutput, TestError) { + Get(oapi, "/greeting/:name", func(c fiber.Ctx, input ParamWithQueryInput) (TestOutput, TestError) { message := "Hello " + input.Name if input.Lang == "fr" { message = "Bonjour " + input.Name @@ -196,7 +196,7 @@ func TestGetOApi_MissingParamValidation(t *testing.T) { }() // This should panic because the "missing" parameter doesn't exist in the path - Get(oapi, "/users/:name", func(c *fiber.Ctx, input MissingParamInput) (TestOutput, TestError) { + Get(oapi, "/users/:name", func(c fiber.Ctx, input MissingParamInput) (TestOutput, TestError) { return TestOutput{Message: "This should not work"}, TestError{} }, OpenAPIOptions{ OperationID: "should-fail", @@ -208,7 +208,7 @@ func TestGetOApi_EmptyPath(t *testing.T) { oapi := New(app) // Test with simple path (no parameters) - Get(oapi, "/health", func(c *fiber.Ctx, input struct{}) (TestOutput, TestError) { + Get(oapi, "/health", func(c fiber.Ctx, input struct{}) (TestOutput, TestError) { return TestOutput{Message: "OK"}, TestError{} }, OpenAPIOptions{ OperationID: "health-check", @@ -235,7 +235,7 @@ func TestGetOApi_ErrorHandling(t *testing.T) { oapi := New(app) // Test with error handling - Get(oapi, "/users/:name", func(c *fiber.Ctx, input SingleParamInput) (TestOutput, TestError) { + Get(oapi, "/users/:name", func(c fiber.Ctx, input SingleParamInput) (TestOutput, TestError) { if input.Name == "error" { return TestOutput{}, TestError{StatusCode: 404, Message: "User not found"} } @@ -276,7 +276,7 @@ func TestGetOApi_OperationStorage(t *testing.T) { ID string `path:"id"` } - Get(oapi, "/test/:id", func(c *fiber.Ctx, input TestInput) (TestOutput, TestError) { + Get(oapi, "/test/:id", func(c fiber.Ctx, input TestInput) (TestOutput, TestError) { return TestOutput{Message: "test"}, TestError{} }, OpenAPIOptions{ OperationID: "test-operation", @@ -322,7 +322,7 @@ func TestGetOApi_Validation(t *testing.T) { oapi := New(app) // Test with advanced validation - Get(oapi, "/users/:name", func(c *fiber.Ctx, input ValidationInput) (TestOutput, TestError) { + Get(oapi, "/users/:name", func(c fiber.Ctx, input ValidationInput) (TestOutput, TestError) { return TestOutput{ Message: fmt.Sprintf("Valid user: %s, email: %s, age: %d", input.Name, input.Email, input.Age), }, TestError{} @@ -386,7 +386,7 @@ func TestGetOApi_ValidationRequired(t *testing.T) { oapi := New(app) // Test with required field - Get(oapi, "/users/:name", func(c *fiber.Ctx, input SingleParamInput) (TestOutput, TestError) { + Get(oapi, "/users/:name", func(c fiber.Ctx, input SingleParamInput) (TestOutput, TestError) { return TestOutput{Message: "Hello " + input.Name}, TestError{} }, OpenAPIOptions{ OperationID: "required-field-test", @@ -399,7 +399,7 @@ func TestGetOApi_ValidationRequired(t *testing.T) { Required string `query:"required" validate:"required"` } - Get(oapi, "/test/:name", func(c *fiber.Ctx, input QueryRequiredInput) (TestOutput, TestError) { + Get(oapi, "/test/:name", func(c fiber.Ctx, input QueryRequiredInput) (TestOutput, TestError) { return TestOutput{Message: "Valid"}, TestError{} }, OpenAPIOptions{ OperationID: "query-required-test", diff --git a/go.mod b/go.mod index 57015d5..85f1cc1 100644 --- a/go.mod +++ b/go.mod @@ -1,31 +1,34 @@ -module github.com/labbs/fiber-oapi +module github.com/labbs/fiber-oapi/v3 -go 1.25.0 +go 1.26.0 require ( github.com/go-playground/validator/v10 v10.30.2 - github.com/gofiber/fiber/v2 v2.52.13 + github.com/gofiber/fiber/v3 v3.3.0 github.com/stretchr/testify v1.11.1 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/andybalholm/brotli v1.2.0 // indirect + github.com/andybalholm/brotli v1.2.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/gabriel-vasile/mimetype v1.4.13 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/gofiber/schema v1.7.1 // indirect + github.com/gofiber/utils/v2 v2.0.6 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/philhofer/fwd v1.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rivo/uniseg v0.4.7 // indirect + github.com/tinylib/msgp v1.6.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.66.0 // indirect - golang.org/x/crypto v0.49.0 // indirect - golang.org/x/sys v0.42.0 // indirect - golang.org/x/text v0.35.0 // indirect + github.com/valyala/fasthttp v1.71.0 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.54.0 // indirect + golang.org/x/sys v0.44.0 // indirect + golang.org/x/text v0.37.0 // indirect ) diff --git a/go.sum b/go.sum index 6134035..f2ae6bb 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,9 @@ -github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= -github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= +github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro= +github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fxamacker/cbor/v2 v2.9.2 h1:X4Ksno9+x3cz0TZv69ec1hxP/+tymuR8PXQJyDwfh78= +github.com/fxamacker/cbor/v2 v2.9.2/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= @@ -12,40 +14,48 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ= github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc= -github.com/gofiber/fiber/v2 v2.52.13 h1:TOKP64iqC9b5P49VrBW5tHhUOvDyrtJ0xePEfzJbCbk= -github.com/gofiber/fiber/v2 v2.52.13/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/gofiber/fiber/v3 v3.3.0 h1:QBd3sYCqdy6Qs5gJYzSw4I4SbqL204jPqpdub/ueiw8= +github.com/gofiber/fiber/v3 v3.3.0/go.mod h1:YH7/TAoRaU4kF8slDCtQuFJ1NzC+3MtxUI4KfvQtaIA= +github.com/gofiber/schema v1.7.1 h1:oSJBKdgP8JeIME4TQSAqlNKTU2iBB+2RNmKi8Nsc+TI= +github.com/gofiber/schema v1.7.1/go.mod h1:A/X5Ffyru4p9eBdp99qu+nzviHzQiZ7odLT+TwxWhbk= +github.com/gofiber/utils/v2 v2.0.6 h1:7fXYy7nSsyqbH0GQUMtK4Kwjy4J7R5742VM7JsZxzOs= +github.com/gofiber/utils/v2 v2.0.6/go.mod h1:p7mAHAk3+oUK10ZX2xTw9fZQixb4hCg8SKd4IH2xroU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.17 h1:78v8ZlW0bP43XfmAfPsdXcoNCelfMHsDmd/pkENfrjQ= -github.com/mattn/go-runewidth v0.0.17/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4= +github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= +github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= +github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/shamaton/msgpack/v3 v3.1.2 h1:d5gWAIyMU4M0WgDjz6IFSCuXJUA2dFwRHBpDclE8CLw= +github.com/shamaton/msgpack/v3 v3.1.2/go.mod h1:DcQG8jrdrQCIxr3HlMYkiXdMhK+KfN2CitkyzsQV4uc= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tinylib/msgp v1.6.4 h1:mOwYbyYDLPj35mkA2BjjYejgJk9BuHxDdvRnb6v2ZcQ= +github.com/tinylib/msgp v1.6.4/go.mod h1:RSp0LW9oSxFut3KzESt5Voq4GVWyS+PSulT77roAqEA= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.66.0 h1:M87A0Z7EayeyNaV6pfO3tUTUiYO0dZfEJnRGXTVNuyU= -github.com/valyala/fasthttp v1.66.0/go.mod h1:Y4eC+zwoocmXSVCB1JmhNbYtS7tZPRI2ztPB72EVObs= +github.com/valyala/fasthttp v1.71.0 h1:tepR7H+Guh9VUqxxcPggYi8R3lGUu2Rsdh+z7/FCY3k= +github.com/valyala/fasthttp v1.71.0/go.mod h1:z1sDUvOShhXq/C9mwH/fSm1Vb71tUJwmQdgkBrBNwnA= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= +golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= +golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= +golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= +golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/group.go b/group.go index e56b323..6818100 100644 --- a/group.go +++ b/group.go @@ -1,7 +1,7 @@ package fiberoapi import ( - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // OApiGroup wraps a fiber.Router and adds OpenAPI methods @@ -27,8 +27,7 @@ func (g *OApiGroup) Use(middleware fiber.Handler) { // Group creates a new OApiGroup that wraps a fiber.Router func (app *OApiApp) Group(prefix string, handlers ...fiber.Handler) *OApiGroup { - // Create the actual fiber group - fiberGroup := app.f.Group(prefix, handlers...) + fiberGroup := app.f.Group(prefix, handlersToAny(handlers)...) return &OApiGroup{ Router: fiberGroup, // Embed the fiber.Router @@ -39,11 +38,9 @@ func (app *OApiApp) Group(prefix string, handlers ...fiber.Handler) *OApiGroup { // Group creates a new sub-group within this group func (g *OApiGroup) Group(prefix string, handlers ...fiber.Handler) *OApiGroup { - // Create full prefix by combining current prefix with new prefix fullPrefix := g.prefix + prefix - // Create the fiber group from the parent app - fiberGroup := g.oapi.f.Group(fullPrefix, handlers...) + fiberGroup := g.oapi.f.Group(fullPrefix, handlersToAny(handlers)...) return &OApiGroup{ Router: fiberGroup, @@ -52,6 +49,14 @@ func (g *OApiGroup) Group(prefix string, handlers ...fiber.Handler) *OApiGroup { } } +func handlersToAny(handlers []fiber.Handler) []any { + out := make([]any, len(handlers)) + for i, h := range handlers { + out[i] = h + } + return out +} + // Group creates a new group from an OApiRouter (app or group) func Group(router OApiRouter, prefix string, handlers ...fiber.Handler) *OApiGroup { if app, ok := router.(*OApiApp); ok { diff --git a/group_test.go b/group_test.go index 69c6442..702ad3f 100644 --- a/group_test.go +++ b/group_test.go @@ -3,7 +3,7 @@ package fiberoapi import ( "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/stretchr/testify/assert" ) @@ -27,7 +27,7 @@ func TestGroupFunctionality(t *testing.T) { initialOpCount := len(oapi.GetOperations()) // Add a route to the group using the unified Get function - Get(v1, "/users/:id", func(c *fiber.Ctx, input struct { + Get(v1, "/users/:id", func(c fiber.Ctx, input struct { ID int `path:"id"` }) (struct { ID int `json:"id"` @@ -58,7 +58,7 @@ func TestGroupWrapper(t *testing.T) { v1 := oapi.Group("/api/v1") // Test that the wrapper correctly registers operations - Post(v1, "/users", func(c *fiber.Ctx, input struct { + Post(v1, "/users", func(c fiber.Ctx, input struct { Name string `json:"name"` }) (struct { ID int `json:"id"` @@ -102,7 +102,7 @@ func TestNestedGroups(t *testing.T) { assert.Equal(t, "/api/v1/users", users.GetPrefix()) // Add an operation to the deeply nested group - Get(users, "/:id", func(c *fiber.Ctx, input struct { + Get(users, "/:id", func(c fiber.Ctx, input struct { ID int `path:"id"` }) (struct { ID int `json:"id"` diff --git a/header_params_test.go b/header_params_test.go index de73167..d4aacee 100644 --- a/header_params_test.go +++ b/header_params_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -34,7 +34,7 @@ func TestHeaderParameterBinding(t *testing.T) { app := fiber.New() oapi := New(app) - Get(oapi, "/test", func(c *fiber.Ctx, input HeaderTestInput) (HeaderTestOutput, HeaderTestError) { + Get(oapi, "/test", func(c fiber.Ctx, input HeaderTestInput) (HeaderTestOutput, HeaderTestError) { return HeaderTestOutput{ RequestID: input.RequestID, UserAgent: input.UserAgent, @@ -69,7 +69,7 @@ func TestHeaderParameterValidation(t *testing.T) { app := fiber.New() oapi := New(app) - Get(oapi, "/test", func(c *fiber.Ctx, input HeaderTestInput) (HeaderTestOutput, HeaderTestError) { + Get(oapi, "/test", func(c fiber.Ctx, input HeaderTestInput) (HeaderTestOutput, HeaderTestError) { return HeaderTestOutput{RequestID: input.RequestID}, HeaderTestError{} }, OpenAPIOptions{ OperationID: "testHeaderValidation", @@ -86,7 +86,7 @@ func TestHeaderParameterOpenAPIGeneration(t *testing.T) { app := fiber.New() oapi := New(app) - Get(oapi, "/test", func(c *fiber.Ctx, input HeaderTestInput) (HeaderTestOutput, HeaderTestError) { + Get(oapi, "/test", func(c fiber.Ctx, input HeaderTestInput) (HeaderTestOutput, HeaderTestError) { return HeaderTestOutput{}, HeaderTestError{} }, OpenAPIOptions{ OperationID: "testHeaderSpec", @@ -150,7 +150,7 @@ func TestHeaderParameterWithPointerTypes(t *testing.T) { RetryCount *int `header:"x-retry-count"` } - Get(oapi, "/test", func(c *fiber.Ctx, input PointerHeaderInput) (PointerHeaderOutput, struct{}) { + Get(oapi, "/test", func(c fiber.Ctx, input PointerHeaderInput) (PointerHeaderOutput, struct{}) { out := PointerHeaderOutput{} if input.TraceID != nil { out.TraceID = *input.TraceID @@ -236,7 +236,7 @@ func TestHeaderNotInRequestBody(t *testing.T) { ID string `json:"id"` } - Post(oapi, "/items", func(c *fiber.Ctx, input PostInputWithHeader) (PostOutput, struct{}) { + Post(oapi, "/items", func(c fiber.Ctx, input PostInputWithHeader) (PostOutput, struct{}) { return PostOutput{ID: "1"}, struct{}{} }, OpenAPIOptions{ OperationID: "createItem", @@ -296,7 +296,7 @@ func TestHeaderTakesPriorityOverBody(t *testing.T) { Name string `json:"name"` } - Post(oapi, "/test", func(c *fiber.Ctx, input PriorityInput) (PriorityOutput, struct{}) { + Post(oapi, "/test", func(c fiber.Ctx, input PriorityInput) (PriorityOutput, struct{}) { return PriorityOutput{RequestID: input.RequestID, Name: input.Name}, struct{}{} }, OpenAPIOptions{ OperationID: "testPriority", @@ -336,7 +336,7 @@ func TestHeaderMixedWithPathAndQuery(t *testing.T) { RequestID string `json:"requestId"` } - Get(oapi, "/items/:id", func(c *fiber.Ctx, input MixedInput) (MixedOutput, struct{}) { + Get(oapi, "/items/:id", func(c fiber.Ctx, input MixedInput) (MixedOutput, struct{}) { return MixedOutput{ ID: input.ID, Filter: input.Filter, diff --git a/json_type_error_test.go b/json_type_error_test.go index e3c65b8..84aa642 100644 --- a/json_type_error_test.go +++ b/json_type_error_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // JSON Type Mismatch Error Handling Tests @@ -45,7 +45,7 @@ func TestJSONTypeMismatchErrors(t *testing.T) { Message string `json:"message"` } - Post(oapi, "/test", func(c *fiber.Ctx, input CreateRequest) (CreateResponse, TestError) { + Post(oapi, "/test", func(c fiber.Ctx, input CreateRequest) (CreateResponse, TestError) { return CreateResponse{Message: "created"}, TestError{} }, OpenAPIOptions{ OperationID: "create", @@ -283,7 +283,7 @@ func TestJSONTypeMismatchWithCustomHandler(t *testing.T) { app := fiber.New() // Create a custom validation error handler - customHandler := func(c *fiber.Ctx, err error) error { + customHandler := func(c fiber.Ctx, err error) error { return c.Status(422).JSON(fiber.Map{ "status": "error", "message": err.Error(), @@ -302,7 +302,7 @@ func TestJSONTypeMismatchWithCustomHandler(t *testing.T) { Result string `json:"result"` } - Post(oapi, "/test", func(c *fiber.Ctx, input TestRequest) (TestResponse, TestError) { + Post(oapi, "/test", func(c fiber.Ctx, input TestRequest) (TestResponse, TestError) { return TestResponse{Result: "OK"}, TestError{} }, OpenAPIOptions{}) @@ -351,7 +351,7 @@ func TestAllTypeMismatches(t *testing.T) { Message string `json:"message"` } - Post(oapi, "/test", func(c *fiber.Ctx, input ComplexRequest) (TestResponse, TestError) { + Post(oapi, "/test", func(c fiber.Ctx, input ComplexRequest) (TestResponse, TestError) { return TestResponse{Message: "OK"}, TestError{} }, OpenAPIOptions{}) @@ -445,7 +445,7 @@ func TestAllTypeMismatches(t *testing.T) { t.Run(tt.name, func(t *testing.T) { req := httptest.NewRequest("POST", "/test", strings.NewReader(tt.body)) req.Header.Set("Content-Type", "application/json") - resp, err := app.Test(req, -1) + resp, err := app.Test(req, fiber.TestConfig{Timeout: 0}) if err != nil { t.Fatalf("Test error: %v", err) } diff --git a/nested_struct_test.go b/nested_struct_test.go index 0401416..bbdf922 100644 --- a/nested_struct_test.go +++ b/nested_struct_test.go @@ -6,7 +6,7 @@ import ( "net/http/httptest" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // Define nested structs for testing @@ -45,7 +45,7 @@ func TestNestedStructSchemaGeneration(t *testing.T) { oapi := New(app) // Add a route with nested structs - Post(oapi, "/users", func(c *fiber.Ctx, req *CreateUserRequest) (*CreateUserResponse, *ErrorResponse) { + Post(oapi, "/users", func(c fiber.Ctx, req *CreateUserRequest) (*CreateUserResponse, *ErrorResponse) { user := User{ ID: 1, Name: req.Name, @@ -210,7 +210,7 @@ func TestDeeplyNestedStructs(t *testing.T) { app := fiber.New() oapi := New(app) - Post(oapi, "/deep", func(c *fiber.Ctx, req *DeepRequest) (*DeepResponse, *ErrorResponse) { + Post(oapi, "/deep", func(c fiber.Ctx, req *DeepRequest) (*DeepResponse, *ErrorResponse) { return &DeepResponse{ Data: req.Outer, Success: true, @@ -264,7 +264,7 @@ func TestArrayOfNestedStructs(t *testing.T) { app := fiber.New() oapi := New(app) - Post(oapi, "/items", func(c *fiber.Ctx, req *ListRequest) (*ListResponse, *ErrorResponse) { + Post(oapi, "/items", func(c fiber.Ctx, req *ListRequest) (*ListResponse, *ErrorResponse) { return &ListResponse{ Items: req.Items, Total: len(req.Items), diff --git a/openapi_hidden_test.go b/openapi_hidden_test.go index 714f13d..1485f1c 100644 --- a/openapi_hidden_test.go +++ b/openapi_hidden_test.go @@ -6,7 +6,7 @@ import ( "net/http/httptest" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -38,7 +38,7 @@ func TestOpenAPIHiddenField_ExcludedFromBodySchema(t *testing.T) { app := fiber.New() oapi := New(app) - Post(oapi, "/items", func(c *fiber.Ctx, input *HiddenFieldInput) (*HiddenFieldOutput, *HiddenFieldError) { + Post(oapi, "/items", func(c fiber.Ctx, input *HiddenFieldInput) (*HiddenFieldOutput, *HiddenFieldError) { return &HiddenFieldOutput{ID: 1, Name: input.Name}, nil }, OpenAPIOptions{ OperationID: "createItem", @@ -90,7 +90,7 @@ func TestOpenAPIHiddenField_ExcludedFromQueryParams(t *testing.T) { app := fiber.New() oapi := New(app) - Get(oapi, "/search", func(c *fiber.Ctx, input HiddenQueryInput) (*HiddenFieldOutput, *HiddenFieldError) { + Get(oapi, "/search", func(c fiber.Ctx, input HiddenQueryInput) (*HiddenFieldOutput, *HiddenFieldError) { return &HiddenFieldOutput{ID: 1, Name: input.Name}, nil }, OpenAPIOptions{ OperationID: "searchItems", diff --git a/post_test.go b/post_test.go index 0b4dfb6..5a19758 100644 --- a/post_test.go +++ b/post_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // Test structs pour POST @@ -51,7 +51,7 @@ func TestPostOApi_SimplePost(t *testing.T) { oapi := New(app) // Test with simple POST (JSON body only) - Post(oapi, "/users", func(c *fiber.Ctx, input PostUserInput) (PostOutput, PostError) { + Post(oapi, "/users", func(c fiber.Ctx, input PostUserInput) (PostOutput, PostError) { return PostOutput{ ID: "user_123", Message: fmt.Sprintf("User %s created successfully", input.Username), @@ -95,7 +95,7 @@ func TestPostOApi_WithPathParams(t *testing.T) { oapi := New(app) // Test with POST + path parameters - Post(oapi, "/groups/:groupId/users", func(c *fiber.Ctx, input PostUserWithPathInput) (PostOutput, PostError) { + Post(oapi, "/groups/:groupId/users", func(c fiber.Ctx, input PostUserWithPathInput) (PostOutput, PostError) { return PostOutput{ ID: "user_456", Message: fmt.Sprintf("User %s added to group %s", input.Username, input.GroupID), @@ -138,7 +138,7 @@ func TestPostOApi_Validation(t *testing.T) { app := fiber.New() oapi := New(app) - Post(oapi, "/users", func(c *fiber.Ctx, input PostUserInput) (PostOutput, PostError) { + Post(oapi, "/users", func(c fiber.Ctx, input PostUserInput) (PostOutput, PostError) { return PostOutput{ ID: "user_789", Message: "User created", @@ -243,7 +243,7 @@ func TestPostOApi_ComplexValidation(t *testing.T) { // Test with complex validation (arrays, nested validation) Post(oapi, "/categories/:categoryId/products", - func(c *fiber.Ctx, input PostProductInput) (PostOutput, PostError) { + func(c fiber.Ctx, input PostProductInput) (PostOutput, PostError) { return PostOutput{ ID: "product_999", Message: fmt.Sprintf("Product %s created in category %s", input.Name, input.CategoryID), @@ -355,7 +355,7 @@ func TestPostOApi_ErrorHandling(t *testing.T) { oapi := New(app) // Test with custom error handling - Post(oapi, "/users", func(c *fiber.Ctx, input PostUserInput) (PostOutput, PostError) { + Post(oapi, "/users", func(c fiber.Ctx, input PostUserInput) (PostOutput, PostError) { if input.Username == "forbidden" { return PostOutput{}, PostError{ StatusCode: 403, @@ -438,7 +438,7 @@ func TestPostOApi_OperationStorage(t *testing.T) { // Check that POST operations are properly stored initialCount := len(oapi.operations) - Post(oapi, "/test", func(c *fiber.Ctx, input PostUserInput) (PostOutput, PostError) { + Post(oapi, "/test", func(c fiber.Ctx, input PostUserInput) (PostOutput, PostError) { return PostOutput{Message: "test"}, PostError{} }, OpenAPIOptions{ OperationID: "test-post-operation", diff --git a/put_test.go b/put_test.go index 9a074bb..1941852 100644 --- a/put_test.go +++ b/put_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // Test structs pour PUT @@ -47,7 +47,7 @@ func TestPutOApi_SimplePut(t *testing.T) { oapi := New(app) // Test with simple PUT (path param + JSON body) - Put(oapi, "/users/:id", func(c *fiber.Ctx, input PutUserInput) (PutOutput, PutError) { + Put(oapi, "/users/:id", func(c fiber.Ctx, input PutUserInput) (PutOutput, PutError) { return PutOutput{ ID: input.ID, Message: fmt.Sprintf("User %s updated successfully", input.ID), @@ -95,7 +95,7 @@ func TestPutOApi_MultiplePathParams(t *testing.T) { oapi := New(app) // Test with PUT + multiple path parameters - Put(oapi, "/categories/:categoryId/products/:productId", func(c *fiber.Ctx, input PutProductInput) (PutOutput, PutError) { + Put(oapi, "/categories/:categoryId/products/:productId", func(c fiber.Ctx, input PutProductInput) (PutOutput, PutError) { return PutOutput{ ID: input.ProductID, Message: fmt.Sprintf("Product %s updated in category %s", input.ProductID, input.CategoryID), @@ -144,7 +144,7 @@ func TestPutOApi_Validation(t *testing.T) { app := fiber.New() oapi := New(app) - Put(oapi, "/users/:id", func(c *fiber.Ctx, input PutUserInput) (PutOutput, PutError) { + Put(oapi, "/users/:id", func(c fiber.Ctx, input PutUserInput) (PutOutput, PutError) { return PutOutput{ ID: input.ID, Message: "User updated", @@ -263,7 +263,7 @@ func TestPutOApi_ErrorHandling(t *testing.T) { oapi := New(app) // Test with custom error handling - Put(oapi, "/users/:id", func(c *fiber.Ctx, input PutUserInput) (PutOutput, PutError) { + Put(oapi, "/users/:id", func(c fiber.Ctx, input PutUserInput) (PutOutput, PutError) { if input.ID == "notfound" { return PutOutput{}, PutError{ StatusCode: 404, @@ -374,7 +374,7 @@ func TestPutOApi_OperationStorage(t *testing.T) { // Check that PUT operations are properly stored initialCount := len(oapi.operations) - Put(oapi, "/test/:id", func(c *fiber.Ctx, input PutUserInput) (PutOutput, PutError) { + Put(oapi, "/test/:id", func(c fiber.Ctx, input PutUserInput) (PutOutput, PutError) { return PutOutput{Message: "test", Updated: true}, PutError{} }, OpenAPIOptions{ OperationID: "test-put-operation", diff --git a/serialization_error_test.go b/serialization_error_test.go index e4c7327..4c34164 100644 --- a/serialization_error_test.go +++ b/serialization_error_test.go @@ -6,7 +6,7 @@ import ( "net/http/httptest" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // UnserializableOutput contains a channel which cannot be serialized to JSON @@ -27,7 +27,7 @@ func TestResponseSerializationError(t *testing.T) { oapi := New(app) // Handler that returns an unserializable output (contains a channel) - Get(oapi, "/unserializable", func(c *fiber.Ctx, input SerializationTestInput) (UnserializableOutput, *SerializationTestError) { + Get(oapi, "/unserializable", func(c fiber.Ctx, input SerializationTestInput) (UnserializableOutput, *SerializationTestError) { return UnserializableOutput{ Name: "test", Channel: make(chan string), // This will fail JSON marshaling @@ -74,7 +74,7 @@ func TestErrorSerializationError(t *testing.T) { oapi := New(app) // Handler that returns an unserializable error - Get(oapi, "/unserializable-error", func(c *fiber.Ctx, input SerializationTestInput) (map[string]string, *UnserializableError) { + Get(oapi, "/unserializable-error", func(c fiber.Ctx, input SerializationTestInput) (map[string]string, *UnserializableError) { return nil, &UnserializableError{ StatusCode: 400, Channel: make(chan string), // This will fail JSON marshaling diff --git a/time_type_test.go b/time_type_test.go index 45e0b74..60b2bc1 100644 --- a/time_type_test.go +++ b/time_type_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) type Workspace struct { @@ -27,7 +27,7 @@ func TestTimeTypeRendersAsDateTimeString(t *testing.T) { app := fiber.New() oapi := New(app) - Post(oapi, "/workspaces", func(c *fiber.Ctx, req *EmptyRequest) (*WorkspaceResponse, *ErrorResponse) { + Post(oapi, "/workspaces", func(c fiber.Ctx, req *EmptyRequest) (*WorkspaceResponse, *ErrorResponse) { return &WorkspaceResponse{}, nil }, OpenAPIOptions{ OperationID: "listWorkspaces", @@ -87,7 +87,7 @@ func TestPointerTimeTypeRendersAsDateTimeString(t *testing.T) { app := fiber.New() oapi := New(app) - Post(oapi, "/events", func(c *fiber.Ctx, req *EmptyRequest) (*EventWithPointerTime, *ErrorResponse) { + Post(oapi, "/events", func(c fiber.Ctx, req *EmptyRequest) (*EventWithPointerTime, *ErrorResponse) { return &EventWithPointerTime{}, nil }, OpenAPIOptions{ OperationID: "createEvent", @@ -129,7 +129,7 @@ func TestTimeTypeAsTopLevelHandlerRuntime(t *testing.T) { OpenAPIDocsPath: "/docs", }) - Post(oapi, "/timestamp", func(c *fiber.Ctx, req time.Time) (time.Time, *ErrorResponse) { + Post(oapi, "/timestamp", func(c fiber.Ctx, req time.Time) (time.Time, *ErrorResponse) { return req, nil }, OpenAPIOptions{OperationID: "echoTimestamp"}) @@ -160,7 +160,7 @@ func TestTimeTypeAsTopLevelInputAndOutput(t *testing.T) { app := fiber.New() oapi := New(app) - Post(oapi, "/timestamp", func(c *fiber.Ctx, req *time.Time) (*time.Time, *ErrorResponse) { + Post(oapi, "/timestamp", func(c fiber.Ctx, req *time.Time) (*time.Time, *ErrorResponse) { return req, nil }, OpenAPIOptions{ OperationID: "echoTimestamp", @@ -217,11 +217,11 @@ func TestPrimitiveAndSliceTopLevelSchemasInline(t *testing.T) { OpenAPIDocsPath: "/docs", }) - Post(oapi, "/echo-string", func(c *fiber.Ctx, req string) (string, *ErrorResponse) { + Post(oapi, "/echo-string", func(c fiber.Ctx, req string) (string, *ErrorResponse) { return req, nil }, OpenAPIOptions{OperationID: "echoString"}) - Post(oapi, "/echo-tags", func(c *fiber.Ctx, req []string) ([]string, *ErrorResponse) { + Post(oapi, "/echo-tags", func(c fiber.Ctx, req []string) ([]string, *ErrorResponse) { return req, nil }, OpenAPIOptions{OperationID: "echoTags"}) @@ -293,7 +293,7 @@ func TestTimeTypeAsTopLevelErrorBody(t *testing.T) { app := fiber.New() oapi := New(app) - Post(oapi, "/timestamp-error", func(c *fiber.Ctx, req *EmptyRequest) (*EmptyRequest, *time.Time) { + Post(oapi, "/timestamp-error", func(c fiber.Ctx, req *EmptyRequest) (*EmptyRequest, *time.Time) { return &EmptyRequest{}, nil }, OpenAPIOptions{ OperationID: "timestampError", diff --git a/types.go b/types.go index c9917ce..537c885 100644 --- a/types.go +++ b/types.go @@ -3,7 +3,7 @@ package fiberoapi import ( "reflect" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // OApiRouter interface that both OApiApp and OApiGroup implement @@ -44,7 +44,7 @@ func (o *OApiApp) Listen(addr string) error { } // HandlerFunc represents a handler function with typed input and output -type HandlerFunc[TInput any, TOutput any, TError any] func(c *fiber.Ctx, input TInput) (TOutput, TError) +type HandlerFunc[TInput any, TOutput any, TError any] func(c fiber.Ctx, input TInput) (TOutput, TError) // PathInfo represents information about a path parameter type PathInfo struct { @@ -55,11 +55,11 @@ type PathInfo struct { // ValidationErrorHandler is a function type for handling validation errors // It receives the fiber context and the validation error, and returns a fiber error response -type ValidationErrorHandler func(c *fiber.Ctx, err error) error +type ValidationErrorHandler func(c fiber.Ctx, err error) error // AuthErrorHandler is a function type for handling authentication/authorization errors // It receives the fiber context and the AuthError, and returns a fiber error response -type AuthErrorHandler func(c *fiber.Ctx, err *AuthError) error +type AuthErrorHandler func(c fiber.Ctx, err *AuthError) error // Config represents configuration for the OApi wrapper type Config struct { diff --git a/validation_test.go b/validation_test.go index 7a0499b..21c30d7 100644 --- a/validation_test.go +++ b/validation_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v3" ) // Advanced tests for validation with validator @@ -32,7 +32,7 @@ func TestAdvancedValidation_UserCreate(t *testing.T) { app := fiber.New() oapi := New(app) - Get(oapi, "/users/:username", func(c *fiber.Ctx, input UserCreateInput) (TestOutput, TestError) { + Get(oapi, "/users/:username", func(c fiber.Ctx, input UserCreateInput) (TestOutput, TestError) { return TestOutput{ Message: fmt.Sprintf("Valid user: %s, %s, age %d, role %s", input.Username, input.Email, input.Age, input.Role), @@ -135,7 +135,7 @@ func TestAdvancedValidation_Product(t *testing.T) { oapi := New(app) Get(oapi, "/categories/:categoryId/products/:productId", - func(c *fiber.Ctx, input ProductInput) (TestOutput, TestError) { + func(c fiber.Ctx, input ProductInput) (TestOutput, TestError) { return TestOutput{ Message: fmt.Sprintf("Product %s in category %s, price range: %.2f-%.2f, in stock: %t", input.ProductID, input.CategoryID, input.MinPrice, input.MaxPrice, input.InStock), @@ -230,7 +230,7 @@ func TestValidation_CustomMessages(t *testing.T) { Name string `path:"name" validate:"required,min=3"` } - Get(oapi, "/simple/:name", func(c *fiber.Ctx, input SimpleInput) (TestOutput, TestError) { + Get(oapi, "/simple/:name", func(c fiber.Ctx, input SimpleInput) (TestOutput, TestError) { return TestOutput{Message: "Valid"}, TestError{} }, OpenAPIOptions{ OperationID: "simple-validation", From 4640fa16a791f24c28dfdf1927f2fd149459e726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Mouton?= Date: Fri, 22 May 2026 19:31:56 +0200 Subject: [PATCH 2/4] Refactor path parameter tags to use 'uri:' for Fiber v3 compatibility --- .gitignore | 5 + README.md | 10 +- _examples/auth/main.go | 4 +- _examples/auto_params/main.go | 2 +- _examples/simple/main.go | 8 +- auth_test.go | 6 +- auto_params_edge_cases_test.go | 6 +- auto_params_test.go | 6 +- common.go | 297 +++++++++------------------------ delete_test.go | 8 +- fiberoapi.go | 3 +- get_oapi_test.go | 18 +- group_test.go | 4 +- header_params_test.go | 2 +- post_test.go | 4 +- put_test.go | 6 +- validation_test.go | 8 +- 17 files changed, 131 insertions(+), 266 deletions(-) diff --git a/.gitignore b/.gitignore index aaadf73..2bcbc76 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,8 @@ go.work.sum # Editor/IDE # .idea/ # .vscode/ + +_examples/auth/auth +_examples/auto_params/demo +_examples/custom_validation_error/custom_validation_error_example +_examples/simple/simple \ No newline at end of file diff --git a/README.md b/README.md index 190ecc5..b3b5d9a 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,10 @@ A Go library that extends Fiber to add automatic OpenAPI documentation generatio go get github.com/labbs/fiber-oapi/v3 ``` +> **Upgrading from v1.x?** v3 tracks Fiber v3 and requires Go 1.26+. Two breaking changes to be aware of: +> - Handlers now take `fiber.Ctx` (struct value) instead of `*fiber.Ctx`. +> - The path-parameter struct tag is now `uri:` instead of `path:` (Fiber v3 binder convention). Query and header tags are unchanged. + ## Quick Start ```go @@ -40,7 +44,7 @@ func main() { fiberoapi.Get(oapi, "/hello/:name", func(c fiber.Ctx, input struct { - Name string `path:"name" validate:"required,min=2"` + Name string `uri:"name" validate:"required,min=2"` }) (fiber.Map, *fiberoapi.ErrorResponse) { return fiber.Map{"message": "Hello " + input.Name}, nil }, @@ -98,7 +102,7 @@ fiberoapi.Method(method, router, path, handler, options) // Custom HTTP method ```go type MyInput struct { - ID string `path:"id" validate:"required"` // Path parameter + ID string `uri:"id" validate:"required"` // Path parameter Filter string `query:"filter" validate:"omitempty"` // Query parameter Auth string `header:"Authorization"` // Header parameter Title string `json:"title" validate:"required,min=1"` // JSON body field @@ -286,7 +290,7 @@ fiberoapi.Put(oapi, "/documents/:id", handler, // Resource-based access via struct tags type UpdateDocInput struct { - DocumentID string `path:"documentId" validate:"required" resource:"document" action:"write"` + DocumentID string `uri:"documentId" validate:"required" resource:"document" action:"write"` Title string `json:"title" validate:"required"` } diff --git a/_examples/auth/main.go b/_examples/auth/main.go index 955bbdb..d09191c 100644 --- a/_examples/auth/main.go +++ b/_examples/auth/main.go @@ -197,11 +197,11 @@ type CreateUserResponse struct { } type DocumentRequest struct { - DocumentID string `path:"documentId" validate:"required"` + DocumentID string `uri:"documentId" validate:"required"` } type UpdateDocumentRequest struct { - DocumentID string `path:"documentId" validate:"required"` + DocumentID string `uri:"documentId" validate:"required"` Title string `json:"title" validate:"required,min=1,max=100"` Content string `json:"content" validate:"required,min=1"` } diff --git a/_examples/auto_params/main.go b/_examples/auto_params/main.go index 22f2a83..3ea9052 100644 --- a/_examples/auto_params/main.go +++ b/_examples/auto_params/main.go @@ -10,7 +10,7 @@ import ( ) type SearchInput struct { - Name string `path:"name" validate:"required"` + Name string `uri:"name" validate:"required"` Email string `query:"email" validate:"omitempty,email"` Age int `query:"age" validate:"omitempty,min=0,max=120"` Active bool `query:"active"` diff --git a/_examples/simple/main.go b/_examples/simple/main.go index 2c12530..963f3e3 100644 --- a/_examples/simple/main.go +++ b/_examples/simple/main.go @@ -8,11 +8,11 @@ import ( ) type ContextRequest struct { - RequestId string `path:"requestId" validate:"required,min=2"` + RequestId string `uri:"requestId" validate:"required,min=2"` } type GetInput struct { - Name string `path:"name" validate:"required,min=2"` + Name string `uri:"name" validate:"required,min=2"` RequestID string `header:"x-request-id" validate:"omitempty"` } @@ -53,7 +53,7 @@ type CreateUserError struct { // Structures pour PUT type UpdateUserInput struct { - ID string `path:"id" validate:"required"` + ID string `uri:"id" validate:"required"` Username string `json:"username" validate:"omitempty,min=3,max=20,alphanum"` Email string `json:"email" validate:"omitempty,email"` Age int `json:"age" validate:"omitempty,min=13,max=120"` @@ -70,7 +70,7 @@ type UpdateUserOutput struct { // Structures pour DELETE type DeleteUserInput struct { - ID string `path:"id" validate:"required"` + ID string `uri:"id" validate:"required"` } type DeleteUserOutput struct { diff --git a/auth_test.go b/auth_test.go index 48326bd..a10ef0a 100644 --- a/auth_test.go +++ b/auth_test.go @@ -135,11 +135,11 @@ func (m *MockAuthService) GetUserPermissions(ctx *AuthContext, resourceType, res // Test structures type TestRequest struct { - ID string `path:"id" validate:"required"` + ID string `uri:"id" validate:"required"` } type TestRequestWithAuth struct { - ID string `path:"id" validate:"required"` + ID string `uri:"id" validate:"required"` ResourceID string `resource:"document" action:"read"` } @@ -365,7 +365,7 @@ func TestScopeBasedAccess(t *testing.T) { // Endpoint requiring write scope Put(oapi, "/documents/:id", func(c fiber.Ctx, input struct { - ID string `path:"id" validate:"required"` + ID string `uri:"id" validate:"required"` Name string `json:"name" validate:"required"` }) (TestResponse, *ErrorResponse) { authCtx, _ := GetAuthContext(c) diff --git a/auto_params_edge_cases_test.go b/auto_params_edge_cases_test.go index 4f593a3..d597bfe 100644 --- a/auto_params_edge_cases_test.go +++ b/auto_params_edge_cases_test.go @@ -41,8 +41,8 @@ func TestAutoParamsEdgeCases(t *testing.T) { t.Run("Struct with unexported fields", func(t *testing.T) { type UnexportedFieldsInput struct { - PublicField string `path:"public" validate:"required"` - _ string `path:"private" validate:"required"` // This should be ignored + PublicField string `uri:"public" validate:"required"` + _ string `uri:"private" validate:"required"` // This should be ignored } type UnexportedOutput struct { @@ -75,7 +75,7 @@ func TestAutoParamsEdgeCases(t *testing.T) { t.Run("Fields with both path and query tags", func(t *testing.T) { type BothTagsInput struct { // This is an invalid case but we should handle it gracefully - Field string `path:"field" query:"field" validate:"required"` + Field string `uri:"field" query:"field" validate:"required"` } type BothTagsOutput struct { diff --git a/auto_params_test.go b/auto_params_test.go index e376527..eaf421d 100644 --- a/auto_params_test.go +++ b/auto_params_test.go @@ -10,7 +10,7 @@ import ( ) type AutoParamsTestInput struct { - UserID string `path:"userId" validate:"required"` + UserID string `uri:"userId" validate:"required"` Name string `query:"name" validate:"required"` Age int `query:"age" validate:"omitempty,min=0,max=120"` Active bool `query:"active"` @@ -124,7 +124,7 @@ func TestMergeWithManualParameters(t *testing.T) { oapi := New(app) type MergeTestInput struct { - UserID string `path:"userId" validate:"required"` + UserID string `uri:"userId" validate:"required"` Name string `query:"name" validate:"required"` Filter string `query:"filter"` } @@ -242,7 +242,7 @@ func TestAutoParamsPointerTypesInline(t *testing.T) { oapi := New(app) type PointerTestInput struct { - ID string `path:"id" validate:"required"` + ID string `uri:"id" validate:"required"` OptionalName *string `query:"optionalName"` RequiredName string `query:"requiredName" validate:"required"` OmitEmpty string `query:"omitEmpty" validate:"omitempty"` diff --git a/common.go b/common.go index 3764aa6..34e499b 100644 --- a/common.go +++ b/common.go @@ -2,10 +2,11 @@ package fiberoapi import ( "encoding/json" + "errors" "fmt" "reflect" - "strconv" "strings" + "sync" "github.com/go-playground/validator/v10" "github.com/gofiber/fiber/v3" @@ -18,113 +19,93 @@ func init() { validate = validator.New() } -// Function to parse input from the request -// parseInput parses the input from the request +// inputShape caches per-type metadata used at request time so we avoid +// re-introspecting the input struct on every request. Built once via sync.OnceValue. +type inputShape struct { + // isStruct is true when the request input is a (possibly pointer-to) struct, + // i.e. eligible for URI/Query/Header binding. + isStruct bool +} + +var shapeCache sync.Map // map[reflect.Type]*inputShape + +// shapeFor returns the cached inputShape for T, computing it lazily once. +func shapeFor[TInput any]() *inputShape { + var zero TInput + t := reflect.TypeOf(zero) + if cached, ok := shapeCache.Load(t); ok { + return cached.(*inputShape) + } + s := &inputShape{ + isStruct: t != nil && dereferenceType(t).Kind() == reflect.Struct, + } + actual, _ := shapeCache.LoadOrStore(t, s) + return actual.(*inputShape) +} + +// parseInput parses the input from the request, delegating URI / Query / Header / +// Body extraction to Fiber's Bind (which caches its own per-type schema). Per-type +// shape metadata is cached locally to avoid re-running reflection on every request. func parseInput[TInput any](app *OApiApp, c fiber.Ctx, path string, options *OpenAPIOptions) (TInput, error) { var input TInput - // Parse path parameters if needed - err := parsePathParams(c, &input) - if err != nil { - return input, err - } + shape := shapeFor[TInput]() - // Parse query parameters - err = parseQueryParams(c, &input) - if err != nil { - return input, err + if shape.isStruct { + if err := c.Bind().URI(&input); err != nil { + return input, err + } + if err := c.Bind().Query(&input); err != nil { + return input, err + } } - // Parse body for POST/PUT methods only if there's content + // Parse body for POST/PUT/PATCH methods only if there's content. + // Body is parsed before headers so that header values take priority over any + // field that the JSON decoder may have populated (e.g. when a header-bound + // field is also sent in the body without a json:"-" tag). method := c.Method() if method == "POST" || method == "PUT" || method == "PATCH" { - // Check if there's content in the body bodyLength := len(c.Body()) contentType := c.Get("Content-Type") - // Parse the body if there's content OR if it's a POST/PUT/PATCH with specified Content-Type if bodyLength > 0 || strings.Contains(contentType, "application/json") || strings.Contains(contentType, "application/x-www-form-urlencoded") { - err = c.Bind().Body(&input) - if err != nil { - // For POST requests without a body, ignore the parsing error + if err := c.Bind().Body(&input); err != nil { + // For POST without a body, tolerate the parsing failure if bodyLength == 0 && method == "POST" { - // It's OK, the POST has no body - ignore the error + // no-op + } else if friendly := translateJSONError(err); friendly != nil { + return input, friendly } else { - // Transform JSON unmarshal type errors into readable validation errors - errMsg := err.Error() - - // Check if error message contains unmarshal type error pattern - if strings.Contains(errMsg, "json: cannot unmarshal") && strings.Contains(errMsg, "into Go struct field") { - // Parse the error message to extract field name and type info - // Format: "json: cannot unmarshal into Go struct field . of type " - parts := strings.Split(errMsg, "into Go struct field ") - if len(parts) == 2 { - afterField := parts[1] - fieldParts := strings.Split(afterField, " of type ") - if len(fieldParts) == 2 { - // Extract field name (after the last dot) - fullFieldName := fieldParts[0] - fieldNameParts := strings.Split(fullFieldName, ".") - fieldName := fieldNameParts[len(fieldNameParts)-1] - - // Extract expected type and trim whitespace - expectedType := strings.TrimSpace(fieldParts[1]) - - // Extract actual type from the first part and trim whitespace - typePart := strings.TrimSpace(strings.TrimPrefix(parts[0], "json: cannot unmarshal ")) - - return input, fmt.Errorf("invalid type for field '%s': expected %s but got %s", - fieldName, expectedType, typePart) - } - } - } else if strings.Contains(errMsg, "json: slice") || strings.Contains(errMsg, "json: map") { - // Handle "json: slice unexpected end of JSON input" and similar errors - // This happens when sending wrong type for slice/map fields - // Try to identify which field caused the error by parsing the request body - fieldName, expectedType, actualType := detectTypeMismatchFromBody(c.Body(), input) - if fieldName != "" { - return input, fmt.Errorf("invalid type for field '%s': expected %s but got %s", - fieldName, expectedType, actualType) - } - // Fallback to generic message if we can't identify the field - return input, fmt.Errorf("invalid JSON: expected array or object but got incompatible type") - } - - // Return original error if no pattern matched return input, err } } } } - // Parse header parameters after body parsing so headers always take priority - // over any values that c.BodyParser may have set via Go field name matching - err = parseHeaderParams(c, &input) - if err != nil { - return input, err + if shape.isStruct { + if err := c.Bind().Header(&input); err != nil { + return input, err + } } // Validate input if enabled in configuration if app.Config().EnableValidation { - err = validate.Struct(input) - if err != nil { + if err := validate.Struct(input); err != nil { return input, err } } // Validate authorization if enabled in configuration and not disabled for this route if app.Config().EnableAuthorization && options != nil { - // Check if security is explicitly disabled for this route if securityValue, ok := options.Security.(string); ok && securityValue == "disabled" { // Skip authorization for this route } else { cfg := app.Config() - // Use per-route security requirements when specified, otherwise fall back to global defaults if routeSecurity, ok := options.Security.([]map[string][]string); ok && len(routeSecurity) > 0 { cfg.DefaultSecurity = routeSecurity } - err = validateAuthorization(c, input, cfg.AuthService, &cfg, options.RequiredRoles, options.RequireAllRoles) - if err != nil { + if err := validateAuthorization(c, input, cfg.AuthService, &cfg, options.RequiredRoles, options.RequireAllRoles); err != nil { return input, err } } @@ -133,6 +114,24 @@ func parseInput[TInput any](app *OApiApp, c fiber.Ctx, path string, options *Ope return input, nil } +// translateJSONError converts low-level json decoder errors into a stable, +// user-facing validation message. Returns nil if err is not a JSON type mismatch. +func translateJSONError(err error) error { + ute, ok := errors.AsType[*json.UnmarshalTypeError](err) + if !ok { + return nil + } + fieldName := ute.Field + if i := strings.LastIndex(fieldName, "."); i >= 0 { + fieldName = fieldName[i+1:] + } + if fieldName == "" { + return fmt.Errorf("invalid JSON: expected %s but got %s", ute.Type.String(), ute.Value) + } + return fmt.Errorf("invalid type for field '%s': expected %s but got %s", + fieldName, ute.Type.String(), ute.Value) +} + // Function to handle custom errors func handleCustomError(c fiber.Ctx, customErr interface{}) error { // Use reflection to extract error information @@ -172,146 +171,6 @@ func isZero(v interface{}) bool { return reflect.ValueOf(v).IsZero() } -// Parse path parameters -func parsePathParams(c fiber.Ctx, input interface{}) error { - inputValue := reflect.ValueOf(input).Elem() - inputType := dereferenceType(reflect.TypeOf(input).Elem()) - - if inputType.Kind() != reflect.Struct { - return nil - } - if inputValue.Kind() == reflect.Ptr { - if inputValue.IsNil() { - return nil - } - inputValue = inputValue.Elem() - } - - for i := 0; i < inputType.NumField(); i++ { - field := inputType.Field(i) - if pathTag := field.Tag.Get("path"); pathTag != "" { - paramValue := c.Params(pathTag) - if paramValue != "" { - fieldValue := inputValue.Field(i) - if fieldValue.CanSet() && fieldValue.Kind() == reflect.String { - fieldValue.SetString(paramValue) - } - } - } - } - - return nil -} - -// Parse query parameters -func parseQueryParams(c fiber.Ctx, input interface{}) error { - inputValue := reflect.ValueOf(input).Elem() - inputType := dereferenceType(reflect.TypeOf(input).Elem()) - - if inputType.Kind() != reflect.Struct { - return nil - } - if inputValue.Kind() == reflect.Ptr { - if inputValue.IsNil() { - return nil - } - inputValue = inputValue.Elem() - } - - for i := 0; i < inputType.NumField(); i++ { - field := inputType.Field(i) - if queryTag := field.Tag.Get("query"); queryTag != "" { - queryValue := c.Query(queryTag) - if queryValue != "" { - fieldValue := inputValue.Field(i) - if fieldValue.CanSet() { - if err := setFieldValue(fieldValue, queryValue); err != nil { - return fmt.Errorf("failed to parse query param %s: %w", queryTag, err) - } - } - } - } - } - - return nil -} - -// Parse header parameters -func parseHeaderParams(c fiber.Ctx, input interface{}) error { - inputValue := reflect.ValueOf(input).Elem() - inputType := dereferenceType(reflect.TypeOf(input).Elem()) - - if inputType.Kind() != reflect.Struct { - return nil - } - if inputValue.Kind() == reflect.Ptr { - if inputValue.IsNil() { - return nil - } - inputValue = inputValue.Elem() - } - - for i := 0; i < inputType.NumField(); i++ { - field := inputType.Field(i) - if headerTag := field.Tag.Get("header"); headerTag != "" { - headerValue := c.Get(headerTag) - if headerValue != "" { - fieldValue := inputValue.Field(i) - if fieldValue.CanSet() { - if err := setFieldValue(fieldValue, headerValue); err != nil { - return fmt.Errorf("failed to parse header param %s: %w", headerTag, err) - } - } - } - } - } - - return nil -} - -// Helper function to set field values with type conversion -func setFieldValue(fieldValue reflect.Value, value string) error { - // Handle pointer types: allocate and recurse into the pointed-to value - if fieldValue.Kind() == reflect.Ptr { - if fieldValue.IsNil() { - fieldValue.Set(reflect.New(fieldValue.Type().Elem())) - } - return setFieldValue(fieldValue.Elem(), value) - } - - switch fieldValue.Kind() { - case reflect.String: - fieldValue.SetString(value) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - if intVal, err := strconv.ParseInt(value, 10, 64); err != nil { - return err - } else { - fieldValue.SetInt(intVal) - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - if uintVal, err := strconv.ParseUint(value, 10, 64); err != nil { - return err - } else { - fieldValue.SetUint(uintVal) - } - case reflect.Float32, reflect.Float64: - if floatVal, err := strconv.ParseFloat(value, fieldValue.Type().Bits()); err != nil { - return err - } else { - fieldValue.SetFloat(floatVal) - } - case reflect.Bool: - if boolVal, err := strconv.ParseBool(value); err != nil { - return err - } else { - fieldValue.SetBool(boolVal) - } - default: - return fmt.Errorf("unsupported field type: %s", fieldValue.Kind()) - } - return nil -} - // Validate that struct parameters match the path func validatePathParams[T any](path string) error { var zero T @@ -339,9 +198,9 @@ func validatePathParams[T any](path string) error { continue } - if pathTag := field.Tag.Get("path"); pathTag != "" { - if !contains(pathParams, pathTag) { - return fmt.Errorf("field %s has path tag '%s' but parameter is not in path %s", field.Name, pathTag, path) + if uriTag := field.Tag.Get("uri"); uriTag != "" { + if !contains(pathParams, uriTag) { + return fmt.Errorf("field %s has uri tag '%s' but parameter is not in path %s", field.Name, uriTag, path) } } } @@ -405,13 +264,11 @@ func extractParametersFromStruct(inputType reflect.Type) []map[string]interface{ continue } - // Process path parameters - if pathTag := field.Tag.Get("path"); pathTag != "" { - // Path parameters are always required regardless of type or validation tags. - // This follows OpenAPI 3.0 specification where path parameters must be required, - // and is enforced here by explicitly setting "required": true at line 289. + // Process path parameters (Fiber v3 binding tag is "uri") + if uriTag := field.Tag.Get("uri"); uriTag != "" { + // Path parameters are always required per OpenAPI 3.0. param := map[string]interface{}{ - "name": pathTag, + "name": uriTag, "in": "path", "required": true, "description": getFieldDescription(field, "Path parameter"), diff --git a/delete_test.go b/delete_test.go index b9b1edd..deabe14 100644 --- a/delete_test.go +++ b/delete_test.go @@ -12,16 +12,16 @@ import ( // Test structs pour DELETE type DeleteUserInput struct { - ID string `path:"id" validate:"required"` + ID string `uri:"id" validate:"required"` } type DeleteProductInput struct { - CategoryID string `path:"categoryId" validate:"required,uuid4"` - ProductID string `path:"productId" validate:"required,uuid4"` + CategoryID string `uri:"categoryId" validate:"required,uuid4"` + ProductID string `uri:"productId" validate:"required,uuid4"` } type DeleteWithQueryInput struct { - ID string `path:"id" validate:"required"` + ID string `uri:"id" validate:"required"` Force bool `query:"force"` Reason string `query:"reason" validate:"omitempty,min=5,max=100"` } diff --git a/fiberoapi.go b/fiberoapi.go index da3a1c1..4c7b2b9 100644 --- a/fiberoapi.go +++ b/fiberoapi.go @@ -925,8 +925,7 @@ func Method[TInput any, TOutput any, TError any]( input, err := parseInput[TInput](app, c, fullPath, &options) if err != nil { // Check for authentication/authorization errors first - var authErr *AuthError - if errors.As(err, &authErr) { + if authErr, ok := errors.AsType[*AuthError](err); ok { if app.config.AuthErrorHandler != nil { return app.config.AuthErrorHandler(c, authErr) } diff --git a/get_oapi_test.go b/get_oapi_test.go index 3941631..9a5cfde 100644 --- a/get_oapi_test.go +++ b/get_oapi_test.go @@ -12,28 +12,28 @@ import ( // Test structs type SingleParamInput struct { - Name string `path:"name" validate:"required"` + Name string `uri:"name" validate:"required"` } type MultiParamInput struct { - UserID string `path:"userId" validate:"required"` - PostID string `path:"postId" validate:"required"` + UserID string `uri:"userId" validate:"required"` + PostID string `uri:"postId" validate:"required"` } type ParamWithQueryInput struct { - Name string `path:"name" validate:"required"` + Name string `uri:"name" validate:"required"` Lang string `query:"lang"` } type ValidationInput struct { - Name string `path:"name" validate:"required,min=2"` + Name string `uri:"name" validate:"required,min=2"` Email string `query:"email" validate:"omitempty,email"` Age int `query:"age" validate:"omitempty,min=0,max=120"` } type MissingParamInput struct { - Name string `path:"name"` - MissingParam string `path:"missing"` // This parameter doesn't exist in the path + Name string `uri:"name"` + MissingParam string `uri:"missing"` // This parameter doesn't exist in the path } // Test outputs @@ -273,7 +273,7 @@ func TestGetOApi_OperationStorage(t *testing.T) { // Input pour le test avec le bon tag type TestInput struct { - ID string `path:"id"` + ID string `uri:"id"` } Get(oapi, "/test/:id", func(c fiber.Ctx, input TestInput) (TestOutput, TestError) { @@ -395,7 +395,7 @@ func TestGetOApi_ValidationRequired(t *testing.T) { // Test with empty name (shouldn't happen with Fiber path params, but let's test anyway) // To simulate, we'll create a structure with a required query field type QueryRequiredInput struct { - Name string `path:"name"` + Name string `uri:"name"` Required string `query:"required" validate:"required"` } diff --git a/group_test.go b/group_test.go index 702ad3f..f34336c 100644 --- a/group_test.go +++ b/group_test.go @@ -28,7 +28,7 @@ func TestGroupFunctionality(t *testing.T) { // Add a route to the group using the unified Get function Get(v1, "/users/:id", func(c fiber.Ctx, input struct { - ID int `path:"id"` + ID int `uri:"id"` }) (struct { ID int `json:"id"` }, struct{}) { @@ -103,7 +103,7 @@ func TestNestedGroups(t *testing.T) { // Add an operation to the deeply nested group Get(users, "/:id", func(c fiber.Ctx, input struct { - ID int `path:"id"` + ID int `uri:"id"` }) (struct { ID int `json:"id"` }, struct{}) { diff --git a/header_params_test.go b/header_params_test.go index d4aacee..55c21c5 100644 --- a/header_params_test.go +++ b/header_params_test.go @@ -325,7 +325,7 @@ func TestHeaderMixedWithPathAndQuery(t *testing.T) { oapi := New(app) type MixedInput struct { - ID string `path:"id" validate:"required"` + ID string `uri:"id" validate:"required"` Filter string `query:"filter"` RequestID string `header:"x-request-id" validate:"required"` } diff --git a/post_test.go b/post_test.go index 5a19758..6e2d94e 100644 --- a/post_test.go +++ b/post_test.go @@ -19,14 +19,14 @@ type PostUserInput struct { } type PostUserWithPathInput struct { - GroupID string `path:"groupId" validate:"required,uuid4"` + GroupID string `uri:"groupId" validate:"required,uuid4"` Username string `json:"username" validate:"required,min=3,max=20"` Email string `json:"email" validate:"required,email"` Role string `json:"role" validate:"required,oneof=member admin"` } type PostProductInput struct { - CategoryID string `path:"categoryId" validate:"required,uuid4"` + CategoryID string `uri:"categoryId" validate:"required,uuid4"` Name string `json:"name" validate:"required,min=2,max=100"` Description string `json:"description" validate:"omitempty,max=1000"` Price float64 `json:"price" validate:"required,min=0"` diff --git a/put_test.go b/put_test.go index 1941852..9f79af4 100644 --- a/put_test.go +++ b/put_test.go @@ -12,7 +12,7 @@ import ( // Test structs pour PUT type PutUserInput struct { - ID string `path:"id" validate:"required"` + ID string `uri:"id" validate:"required"` Username string `json:"username" validate:"omitempty,min=3,max=20,alphanum"` Email string `json:"email" validate:"omitempty,email"` Age int `json:"age" validate:"omitempty,min=13,max=120"` @@ -20,8 +20,8 @@ type PutUserInput struct { } type PutProductInput struct { - CategoryID string `path:"categoryId" validate:"required,uuid4"` - ProductID string `path:"productId" validate:"required,uuid4"` + CategoryID string `uri:"categoryId" validate:"required,uuid4"` + ProductID string `uri:"productId" validate:"required,uuid4"` Name string `json:"name" validate:"omitempty,min=2,max=100"` Description string `json:"description" validate:"omitempty,max=1000"` Price float64 `json:"price" validate:"omitempty,min=0"` diff --git a/validation_test.go b/validation_test.go index 21c30d7..ad5da94 100644 --- a/validation_test.go +++ b/validation_test.go @@ -13,7 +13,7 @@ import ( // Advanced tests for validation with validator type UserCreateInput struct { - Username string `path:"username" validate:"required,min=3,max=20,alphanum"` + Username string `uri:"username" validate:"required,min=3,max=20,alphanum"` Email string `query:"email" validate:"required,email"` Age int `query:"age" validate:"required,min=13,max=120"` Website string `query:"website" validate:"omitempty,url"` @@ -21,8 +21,8 @@ type UserCreateInput struct { } type ProductInput struct { - CategoryID string `path:"categoryId" validate:"required,uuid4"` - ProductID string `path:"productId" validate:"required,numeric"` + CategoryID string `uri:"categoryId" validate:"required,uuid4"` + ProductID string `uri:"productId" validate:"required,numeric"` MinPrice float64 `query:"minPrice" validate:"omitempty,min=0"` MaxPrice float64 `query:"maxPrice" validate:"omitempty,min=0,gtfield=MinPrice"` InStock bool `query:"inStock"` @@ -227,7 +227,7 @@ func TestValidation_CustomMessages(t *testing.T) { oapi := New(app) type SimpleInput struct { - Name string `path:"name" validate:"required,min=3"` + Name string `uri:"name" validate:"required,min=3"` } Get(oapi, "/simple/:name", func(c fiber.Ctx, input SimpleInput) (TestOutput, TestError) { From 2f8a5ad97746f0b8f706c664fe764675942c3de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Mouton?= Date: Fri, 22 May 2026 19:35:41 +0200 Subject: [PATCH 3/4] Fix: Return nil for empty handlers in handlersToAny function --- group.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/group.go b/group.go index 6818100..73775ff 100644 --- a/group.go +++ b/group.go @@ -50,6 +50,9 @@ func (g *OApiGroup) Group(prefix string, handlers ...fiber.Handler) *OApiGroup { } func handlersToAny(handlers []fiber.Handler) []any { + if len(handlers) == 0 { + return nil + } out := make([]any, len(handlers)) for i, h := range handlers { out[i] = h From 589eb1ecede04992091af7e374aafa8fda353dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Mouton?= Date: Fri, 22 May 2026 19:39:32 +0200 Subject: [PATCH 4/4] Update dependencies to latest versions for compatibility with Fiber v3 --- _examples/auth/go.mod | 6 +++--- _examples/auth/go.sum | 12 ++++++------ _examples/auto_params/go.mod | 6 +++--- _examples/auto_params/go.sum | 12 ++++++------ _examples/custom_validation_error/go.mod | 6 +++--- _examples/custom_validation_error/go.sum | 12 ++++++------ _examples/simple/go.mod | 6 +++--- _examples/simple/go.sum | 12 ++++++------ go.mod | 6 +++--- go.sum | 12 ++++++------ 10 files changed, 45 insertions(+), 45 deletions(-) diff --git a/_examples/auth/go.mod b/_examples/auth/go.mod index db10eef..5129084 100644 --- a/_examples/auth/go.mod +++ b/_examples/auth/go.mod @@ -26,9 +26,9 @@ require ( github.com/tinylib/msgp v1.6.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.71.0 // indirect - golang.org/x/crypto v0.51.0 // indirect - golang.org/x/net v0.54.0 // indirect - golang.org/x/sys v0.44.0 // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect golang.org/x/text v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/_examples/auth/go.sum b/_examples/auth/go.sum index f2ae6bb..8636088 100644 --- a/_examples/auth/go.sum +++ b/_examples/auth/go.sum @@ -48,12 +48,12 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= -golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= -golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= -golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= -golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= -golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/_examples/auto_params/go.mod b/_examples/auto_params/go.mod index 8ab1720..ff1dad8 100644 --- a/_examples/auto_params/go.mod +++ b/_examples/auto_params/go.mod @@ -26,9 +26,9 @@ require ( github.com/tinylib/msgp v1.6.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.71.0 // indirect - golang.org/x/crypto v0.51.0 // indirect - golang.org/x/net v0.54.0 // indirect - golang.org/x/sys v0.44.0 // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect golang.org/x/text v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/_examples/auto_params/go.sum b/_examples/auto_params/go.sum index f2ae6bb..8636088 100644 --- a/_examples/auto_params/go.sum +++ b/_examples/auto_params/go.sum @@ -48,12 +48,12 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= -golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= -golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= -golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= -golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= -golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/_examples/custom_validation_error/go.mod b/_examples/custom_validation_error/go.mod index ddea16f..2765517 100644 --- a/_examples/custom_validation_error/go.mod +++ b/_examples/custom_validation_error/go.mod @@ -26,9 +26,9 @@ require ( github.com/tinylib/msgp v1.6.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.71.0 // indirect - golang.org/x/crypto v0.51.0 // indirect - golang.org/x/net v0.54.0 // indirect - golang.org/x/sys v0.44.0 // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect golang.org/x/text v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/_examples/custom_validation_error/go.sum b/_examples/custom_validation_error/go.sum index f2ae6bb..8636088 100644 --- a/_examples/custom_validation_error/go.sum +++ b/_examples/custom_validation_error/go.sum @@ -48,12 +48,12 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= -golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= -golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= -golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= -golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= -golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/_examples/simple/go.mod b/_examples/simple/go.mod index 484e72c..c9f2f75 100644 --- a/_examples/simple/go.mod +++ b/_examples/simple/go.mod @@ -26,9 +26,9 @@ require ( github.com/tinylib/msgp v1.6.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.71.0 // indirect - golang.org/x/crypto v0.51.0 // indirect - golang.org/x/net v0.54.0 // indirect - golang.org/x/sys v0.44.0 // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect golang.org/x/text v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/_examples/simple/go.sum b/_examples/simple/go.sum index f2ae6bb..8636088 100644 --- a/_examples/simple/go.sum +++ b/_examples/simple/go.sum @@ -48,12 +48,12 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= -golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= -golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= -golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= -golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= -golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/go.mod b/go.mod index 85f1cc1..6763d5e 100644 --- a/go.mod +++ b/go.mod @@ -27,8 +27,8 @@ require ( github.com/tinylib/msgp v1.6.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.71.0 // indirect - golang.org/x/crypto v0.51.0 // indirect - golang.org/x/net v0.54.0 // indirect - golang.org/x/sys v0.44.0 // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sys v0.45.0 // indirect golang.org/x/text v0.37.0 // indirect ) diff --git a/go.sum b/go.sum index f2ae6bb..8636088 100644 --- a/go.sum +++ b/go.sum @@ -48,12 +48,12 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= -golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= -golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= -golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= -golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= -golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= -golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=