diff --git a/examples/server/beego/api/gen.go b/examples/server/beego/api/gen.go index 139d25a0..a3163075 100644 --- a/examples/server/beego/api/gen.go +++ b/examples/server/beego/api/gen.go @@ -104,8 +104,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -114,7 +115,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -223,7 +224,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, 400, NewCreateUserErrorResponse(err.Error())) return } @@ -357,8 +358,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []beego.MiddleWare - errHandler OapiErrorHandler + middlewares []beego.MiddleWare + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -376,6 +378,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // beegoHandler wraps an http.HandlerFunc for Beego with path param injection. func beegoHandler(h http.HandlerFunc, pathParams ...string) beego.HandleFunc { return func(ctx *beecontext.Context) { @@ -396,6 +406,9 @@ func RegisterRoutes(router *beego.ControllerRegister, svc ServiceInterface, opts } httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } router.Get("/health", beegoHandler(httpAdapter.HealthCheck)) router.Get("/users", beegoHandler(httpAdapter.ListUsers)) router.Post("/users", beegoHandler(httpAdapter.CreateUser)) diff --git a/examples/server/chi/api/gen.go b/examples/server/chi/api/gen.go index 269632e1..8edcbe62 100644 --- a/examples/server/chi/api/gen.go +++ b/examples/server/chi/api/gen.go @@ -103,8 +103,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -113,7 +114,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -222,7 +223,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, 400, NewCreateUserErrorResponse(err.Error())) return } @@ -356,8 +357,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -375,6 +377,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new chi.Router with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { cfg := &routerConfig{} @@ -388,6 +398,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.Method("GET", "/health", http.HandlerFunc(adapter.HealthCheck)) r.Method("GET", "/users", http.HandlerFunc(adapter.ListUsers)) r.Method("POST", "/users", http.HandlerFunc(adapter.CreateUser)) diff --git a/examples/server/config-variations/custom-service-name/types.gen.go b/examples/server/config-variations/custom-service-name/types.gen.go index a81ce768..59930592 100644 --- a/examples/server/config-variations/custom-service-name/types.gen.go +++ b/examples/server/config-variations/custom-service-name/types.gen.go @@ -102,8 +102,9 @@ type CustomServiceNameInterface interface { // HTTPAdapter adapts the CustomServiceNameInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc CustomServiceNameInterface - errHandler OapiErrorHandler + svc CustomServiceNameInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -112,7 +113,7 @@ func NewHTTPAdapter(svc CustomServiceNameInterface, errHandler OapiErrorHandler) if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -221,7 +222,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -355,8 +356,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -374,6 +376,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new chi.Router with the given service implementation. func NewRouter(svc CustomServiceNameInterface, opts ...RouterOption) chi.Router { cfg := &routerConfig{} @@ -387,6 +397,9 @@ func NewRouter(svc CustomServiceNameInterface, opts ...RouterOption) chi.Router } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.Method("GET", "/health", http.HandlerFunc(adapter.HealthCheck)) r.Method("GET", "/users", http.HandlerFunc(adapter.ListUsers)) r.Method("POST", "/users", http.HandlerFunc(adapter.CreateUser)) diff --git a/examples/server/config-variations/diff-package-multiple-files/models/adapter.go b/examples/server/config-variations/diff-package-multiple-files/models/adapter.go index dfc42a00..f69f1f5c 100644 --- a/examples/server/config-variations/diff-package-multiple-files/models/adapter.go +++ b/examples/server/config-variations/diff-package-multiple-files/models/adapter.go @@ -27,8 +27,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -37,7 +38,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -146,7 +147,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", diff --git a/examples/server/config-variations/diff-package-multiple-files/models/router.go b/examples/server/config-variations/diff-package-multiple-files/models/router.go index 419da38f..77a86ce3 100644 --- a/examples/server/config-variations/diff-package-multiple-files/models/router.go +++ b/examples/server/config-variations/diff-package-multiple-files/models/router.go @@ -4,6 +4,7 @@ package models import ( "net/http" + "github.com/doordash-oss/oapi-codegen-dd/v3/pkg/runtime" "github.com/go-chi/chi/v5" ) @@ -11,8 +12,9 @@ import ( type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -30,6 +32,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new chi.Router with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { cfg := &routerConfig{} @@ -43,6 +53,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.Method("GET", "/health", http.HandlerFunc(adapter.HealthCheck)) r.Method("GET", "/users", http.HandlerFunc(adapter.ListUsers)) r.Method("POST", "/users", http.HandlerFunc(adapter.CreateUser)) diff --git a/examples/server/config-variations/diff-package-single-file/models/adapter.gen.go b/examples/server/config-variations/diff-package-single-file/models/adapter.gen.go index 34df209b..8ec88f75 100644 --- a/examples/server/config-variations/diff-package-single-file/models/adapter.gen.go +++ b/examples/server/config-variations/diff-package-single-file/models/adapter.gen.go @@ -101,8 +101,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -111,7 +112,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -220,7 +221,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -354,8 +355,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -373,6 +375,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new chi.Router with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { cfg := &routerConfig{} @@ -386,6 +396,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.Method("GET", "/health", http.HandlerFunc(adapter.HealthCheck)) r.Method("GET", "/users", http.HandlerFunc(adapter.ListUsers)) r.Method("POST", "/users", http.HandlerFunc(adapter.CreateUser)) diff --git a/examples/server/config-variations/no-service/types.gen.go b/examples/server/config-variations/no-service/types.gen.go index 96049467..374e9358 100644 --- a/examples/server/config-variations/no-service/types.gen.go +++ b/examples/server/config-variations/no-service/types.gen.go @@ -102,8 +102,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -112,7 +113,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -221,7 +222,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -355,8 +356,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -374,6 +376,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new chi.Router with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { cfg := &routerConfig{} @@ -387,6 +397,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.Method("GET", "/health", http.HandlerFunc(adapter.HealthCheck)) r.Method("GET", "/users", http.HandlerFunc(adapter.ListUsers)) r.Method("POST", "/users", http.HandlerFunc(adapter.CreateUser)) diff --git a/examples/server/config-variations/same-package-multiple-files/api/adapter.go b/examples/server/config-variations/same-package-multiple-files/api/adapter.go index 9f8499fb..8dca4eea 100644 --- a/examples/server/config-variations/same-package-multiple-files/api/adapter.go +++ b/examples/server/config-variations/same-package-multiple-files/api/adapter.go @@ -27,8 +27,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -37,7 +38,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -146,7 +147,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, 400, NewError(err.Error())) return } diff --git a/examples/server/config-variations/same-package-multiple-files/api/router.go b/examples/server/config-variations/same-package-multiple-files/api/router.go index 45f690dc..fc2bb5c7 100644 --- a/examples/server/config-variations/same-package-multiple-files/api/router.go +++ b/examples/server/config-variations/same-package-multiple-files/api/router.go @@ -4,6 +4,7 @@ package api import ( "net/http" + "github.com/doordash-oss/oapi-codegen-dd/v3/pkg/runtime" "github.com/go-chi/chi/v5" ) @@ -11,8 +12,9 @@ import ( type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -30,6 +32,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new chi.Router with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { cfg := &routerConfig{} @@ -43,6 +53,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.Method("GET", "/health", http.HandlerFunc(adapter.HealthCheck)) r.Method("GET", "/users", http.HandlerFunc(adapter.ListUsers)) r.Method("POST", "/users", http.HandlerFunc(adapter.CreateUser)) diff --git a/examples/server/config-variations/same-package-single-file/types.gen.go b/examples/server/config-variations/same-package-single-file/types.gen.go index 96049467..374e9358 100644 --- a/examples/server/config-variations/same-package-single-file/types.gen.go +++ b/examples/server/config-variations/same-package-single-file/types.gen.go @@ -102,8 +102,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -112,7 +113,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -221,7 +222,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -355,8 +356,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -374,6 +376,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new chi.Router with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { cfg := &routerConfig{} @@ -387,6 +397,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.Method("GET", "/health", http.HandlerFunc(adapter.HealthCheck)) r.Method("GET", "/users", http.HandlerFunc(adapter.ListUsers)) r.Method("POST", "/users", http.HandlerFunc(adapter.CreateUser)) diff --git a/examples/server/config-variations/zero-endpoints/api/adapter.go b/examples/server/config-variations/zero-endpoints/api/adapter.go index 78764b09..5d213ae5 100644 --- a/examples/server/config-variations/zero-endpoints/api/adapter.go +++ b/examples/server/config-variations/zero-endpoints/api/adapter.go @@ -1,6 +1,10 @@ // Code generated by oapi-codegen. DO NOT EDIT. package api +import ( + "github.com/doordash-oss/oapi-codegen-dd/v3/pkg/runtime" +) + // ServiceInterface defines the service interface for business logic. type ServiceInterface interface { } @@ -8,8 +12,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -18,5 +23,5 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } diff --git a/examples/server/config-variations/zero-endpoints/api/router.go b/examples/server/config-variations/zero-endpoints/api/router.go index 523bfb3f..754e2f96 100644 --- a/examples/server/config-variations/zero-endpoints/api/router.go +++ b/examples/server/config-variations/zero-endpoints/api/router.go @@ -4,6 +4,7 @@ package api import ( "net/http" + "github.com/doordash-oss/oapi-codegen-dd/v3/pkg/runtime" "github.com/go-chi/chi/v5" ) @@ -11,8 +12,9 @@ import ( type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -30,6 +32,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new chi.Router with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { cfg := &routerConfig{} diff --git a/examples/server/echo/api/gen.go b/examples/server/echo/api/gen.go index 177c94bc..674aa63e 100644 --- a/examples/server/echo/api/gen.go +++ b/examples/server/echo/api/gen.go @@ -102,8 +102,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -112,7 +113,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -221,7 +222,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -355,8 +356,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []echo.MiddlewareFunc - errHandler OapiErrorHandler + middlewares []echo.MiddlewareFunc + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -374,6 +376,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter registers routes on the given Echo instance with the service implementation. func NewRouter(e *echo.Echo, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -387,6 +397,9 @@ func NewRouter(e *echo.Echo, svc ServiceInterface, opts ...RouterOption) { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } e.GET("/health", func(c echo.Context) error { adapter.HealthCheck(c.Response(), c.Request()) return nil diff --git a/examples/server/fasthttp/api/gen.go b/examples/server/fasthttp/api/gen.go index 75bca3c8..ba068f55 100644 --- a/examples/server/fasthttp/api/gen.go +++ b/examples/server/fasthttp/api/gen.go @@ -105,8 +105,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -115,7 +116,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -224,7 +225,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, 400, NewCreateUserErrorResponse(err.Error())) return } @@ -358,8 +359,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(fasthttp.RequestHandler) fasthttp.RequestHandler - errHandler OapiErrorHandler + middlewares []func(fasthttp.RequestHandler) fasthttp.RequestHandler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -377,6 +379,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // fasthttpHandler wraps an http.HandlerFunc with path param injection for fasthttp. func fasthttpHandler(h http.HandlerFunc, pathParams ...string) fasthttp.RequestHandler { return func(ctx *fasthttp.RequestCtx) { @@ -403,6 +413,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) *router.Router { r := router.New() httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.GET("/health", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.HealthCheck)) r.GET("/users", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.ListUsers)) r.POST("/users", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.CreateUser)) @@ -435,6 +448,9 @@ func Handler(svc ServiceInterface, opts ...RouterOption) fasthttp.RequestHandler r := router.New() httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.GET("/health", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.HealthCheck)) r.GET("/users", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.ListUsers)) r.POST("/users", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.CreateUser)) diff --git a/examples/server/fiber/api/gen.go b/examples/server/fiber/api/gen.go index 822d37fc..af815130 100644 --- a/examples/server/fiber/api/gen.go +++ b/examples/server/fiber/api/gen.go @@ -103,8 +103,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -113,7 +114,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -222,7 +223,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -356,8 +357,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []fiber.Handler - errHandler OapiErrorHandler + middlewares []fiber.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -375,6 +377,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // fiberHTTPHandler wraps an http.HandlerFunc with path param injection for Fiber. func fiberHTTPHandler(h http.HandlerFunc, pathParams ...string) fiber.Handler { return func(c fiber.Ctx) error { @@ -401,6 +411,9 @@ func NewRouter(app *fiber.App, svc ServiceInterface, opts ...RouterOption) { } httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } app.Get("/health", adaptor.HTTPHandlerFunc(httpAdapter.HealthCheck)) app.Get("/users", adaptor.HTTPHandlerFunc(httpAdapter.ListUsers)) app.Post("/users", adaptor.HTTPHandlerFunc(httpAdapter.CreateUser)) diff --git a/examples/server/gin/api/gen.go b/examples/server/gin/api/gen.go index 06bc0f26..874e802e 100644 --- a/examples/server/gin/api/gen.go +++ b/examples/server/gin/api/gen.go @@ -102,8 +102,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -112,7 +113,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -221,7 +222,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -355,8 +356,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []gin.HandlerFunc - errHandler OapiErrorHandler + middlewares []gin.HandlerFunc + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -374,6 +376,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter registers routes on the given Gin engine with the service implementation. func NewRouter(r *gin.Engine, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -387,6 +397,9 @@ func NewRouter(r *gin.Engine, svc ServiceInterface, opts ...RouterOption) { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.GET("/health", func(c *gin.Context) { adapter.HealthCheck(c.Writer, c.Request) }) diff --git a/examples/server/go-zero/api/gen.go b/examples/server/go-zero/api/gen.go index ce36e66d..3b91cffa 100644 --- a/examples/server/go-zero/api/gen.go +++ b/examples/server/go-zero/api/gen.go @@ -105,8 +105,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -115,7 +116,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -224,7 +225,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, 400, NewCreateUserErrorResponse(err.Error())) return } @@ -358,8 +359,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []rest.Middleware - errHandler OapiErrorHandler + middlewares []rest.Middleware + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -377,6 +379,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // RegisterRoutes registers all routes with the given go-zero server. func RegisterRoutes(server *rest.Server, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -385,6 +395,9 @@ func RegisterRoutes(server *rest.Server, svc ServiceInterface, opts ...RouterOpt } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } routes := []rest.Route{ { @@ -433,6 +446,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) http.Handler { r := router.NewRouter() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } _ = r.Handle("GET", "/health", http.HandlerFunc(adapter.HealthCheck)) _ = r.Handle("GET", "/users", http.HandlerFunc(adapter.ListUsers)) _ = r.Handle("POST", "/users", http.HandlerFunc(adapter.CreateUser)) diff --git a/examples/server/goframe/api/gen.go b/examples/server/goframe/api/gen.go index 269c3cdf..bd352d9b 100644 --- a/examples/server/goframe/api/gen.go +++ b/examples/server/goframe/api/gen.go @@ -103,8 +103,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -113,7 +114,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -222,7 +223,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, 400, NewCreateUserErrorResponse(err.Error())) return } @@ -356,8 +357,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []ghttp.HandlerFunc - errHandler OapiErrorHandler + middlewares []ghttp.HandlerFunc + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -375,6 +377,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter registers routes on the given GoFrame server with the service implementation. func NewRouter(s *ghttp.Server, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -388,6 +398,9 @@ func NewRouter(s *ghttp.Server, svc ServiceInterface, opts ...RouterOption) { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } s.BindHandler("GET:/health", func(r *ghttp.Request) { adapter.HealthCheck(r.Response.Writer, r.Request) }) @@ -420,6 +433,9 @@ func Handler(svc ServiceInterface, opts ...RouterOption) http.Handler { mux := http.NewServeMux() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } mux.HandleFunc("GET /health", adapter.HealthCheck) mux.HandleFunc("GET /users", adapter.ListUsers) mux.HandleFunc("POST /users", adapter.CreateUser) diff --git a/examples/server/gorilla-mux/api/gen.go b/examples/server/gorilla-mux/api/gen.go index 052ba0e6..c73a6aa7 100644 --- a/examples/server/gorilla-mux/api/gen.go +++ b/examples/server/gorilla-mux/api/gen.go @@ -103,8 +103,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -113,7 +114,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -222,7 +223,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, 400, NewCreateUserErrorResponse(err.Error())) return } @@ -356,8 +357,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []mux.MiddlewareFunc - errHandler OapiErrorHandler + middlewares []mux.MiddlewareFunc + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -375,6 +377,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new mux.Router with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) *mux.Router { cfg := &routerConfig{} @@ -388,6 +398,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) *mux.Router { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.HandleFunc("/health", adapter.HealthCheck).Methods("GET") r.HandleFunc("/users", adapter.ListUsers).Methods("GET") r.HandleFunc("/users", adapter.CreateUser).Methods("POST") diff --git a/examples/server/hertz/api/gen.go b/examples/server/hertz/api/gen.go index ffcfec33..1493f15b 100644 --- a/examples/server/hertz/api/gen.go +++ b/examples/server/hertz/api/gen.go @@ -106,8 +106,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -116,7 +117,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -225,7 +226,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, 400, NewCreateUserErrorResponse(err.Error())) return } @@ -359,8 +360,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []app.HandlerFunc - errHandler OapiErrorHandler + middlewares []app.HandlerFunc + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -378,6 +380,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter registers routes on the given Hertz server with the service implementation. func NewRouter(h *server.Hertz, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -391,6 +401,9 @@ func NewRouter(h *server.Hertz, svc ServiceInterface, opts ...RouterOption) { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } h.Handle("GET", "/health", func(ctx context.Context, c *app.RequestContext) { req, err := adaptor.GetCompatRequest(&c.Request) if err != nil { @@ -453,6 +466,9 @@ func Handler(svc ServiceInterface, opts ...RouterOption) http.Handler { mux := http.NewServeMux() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } mux.HandleFunc("GET /health", adapter.HealthCheck) mux.HandleFunc("GET /users", adapter.ListUsers) mux.HandleFunc("POST /users", adapter.CreateUser) diff --git a/examples/server/iris/api/gen.go b/examples/server/iris/api/gen.go index 1a42ba8c..a172eb6e 100644 --- a/examples/server/iris/api/gen.go +++ b/examples/server/iris/api/gen.go @@ -102,8 +102,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -112,7 +113,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -221,7 +222,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -355,8 +356,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []iris.Handler - errHandler OapiErrorHandler + middlewares []iris.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -374,6 +376,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter registers routes on the given Iris application with the service implementation. func NewRouter(app *iris.Application, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -387,6 +397,9 @@ func NewRouter(app *iris.Application, svc ServiceInterface, opts ...RouterOption } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } app.Handle("GET", "/health", func(ctx iris.Context) { adapter.HealthCheck(ctx.ResponseWriter(), ctx.Request()) }) @@ -419,6 +432,9 @@ func Handler(svc ServiceInterface, opts ...RouterOption) http.Handler { mux := http.NewServeMux() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } mux.HandleFunc("GET /health", adapter.HealthCheck) mux.HandleFunc("GET /users", adapter.ListUsers) mux.HandleFunc("POST /users", adapter.CreateUser) diff --git a/examples/server/kratos/api/gen.go b/examples/server/kratos/api/gen.go index 63a5b7bd..d6cdb308 100644 --- a/examples/server/kratos/api/gen.go +++ b/examples/server/kratos/api/gen.go @@ -104,8 +104,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -114,7 +115,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -223,7 +224,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, 400, NewCreateUserErrorResponse(err.Error())) return } @@ -357,8 +358,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -376,6 +378,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // RegisterRoutes registers all routes with the given Kratos HTTP server. // It creates a gorilla/mux router and mounts it using HandlePrefix. func RegisterRoutes(server *kratoshttp.Server, svc ServiceInterface, opts ...RouterOption) { @@ -394,6 +404,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) http.Handler { r := mux.NewRouter() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.HandleFunc("/health", adapter.HealthCheck).Methods("GET") r.HandleFunc("/users", adapter.ListUsers).Methods("GET") r.HandleFunc("/users", adapter.CreateUser).Methods("POST") diff --git a/examples/server/std-http/api/gen.go b/examples/server/std-http/api/gen.go index 7778eb34..d0330c53 100644 --- a/examples/server/std-http/api/gen.go +++ b/examples/server/std-http/api/gen.go @@ -102,8 +102,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -112,7 +113,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -221,7 +222,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, 400, NewCreateUserErrorResponse(err.Error())) return } @@ -355,8 +356,9 @@ func (a *HTTPAdapter) DeleteUser(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -374,6 +376,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new http.ServeMux with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) *http.ServeMux { cfg := &routerConfig{} @@ -384,6 +394,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) *http.ServeMux { mux := http.NewServeMux() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } mux.HandleFunc("GET /health", applyMiddleware(http.HandlerFunc(adapter.HealthCheck), cfg.middlewares...)) mux.HandleFunc("GET /users", applyMiddleware(http.HandlerFunc(adapter.ListUsers), cfg.middlewares...)) mux.HandleFunc("POST /users", applyMiddleware(http.HandlerFunc(adapter.CreateUser), cfg.middlewares...)) diff --git a/examples/server/test/beego/testcase/adapter.gen.go b/examples/server/test/beego/testcase/adapter.gen.go index 1e7fac14..3e60563e 100644 --- a/examples/server/test/beego/testcase/adapter.gen.go +++ b/examples/server/test/beego/testcase/adapter.gen.go @@ -141,8 +141,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -151,7 +152,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -269,7 +270,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1340,7 +1341,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1393,7 +1394,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1441,8 +1442,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []beego.MiddleWare - errHandler OapiErrorHandler + middlewares []beego.MiddleWare + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1460,6 +1462,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // beegoHandler wraps an http.HandlerFunc for Beego with path param injection. func beegoHandler(h http.HandlerFunc, pathParams ...string) beego.HandleFunc { return func(ctx *beecontext.Context) { @@ -1480,6 +1490,9 @@ func RegisterRoutes(router *beego.ControllerRegister, svc ServiceInterface, opts } httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } router.Get("/health", beegoHandler(httpAdapter.HealthCheck)) router.Get("/users", beegoHandler(httpAdapter.ListUsers)) router.Post("/users", beegoHandler(httpAdapter.CreateUser)) diff --git a/examples/server/test/chi/testcase/adapter.gen.go b/examples/server/test/chi/testcase/adapter.gen.go index e50ad7d9..75302b1a 100644 --- a/examples/server/test/chi/testcase/adapter.gen.go +++ b/examples/server/test/chi/testcase/adapter.gen.go @@ -140,8 +140,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -150,7 +151,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -268,7 +269,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1339,7 +1340,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1392,7 +1393,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1440,8 +1441,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1459,6 +1461,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new chi.Router with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { cfg := &routerConfig{} @@ -1472,6 +1482,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) chi.Router { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.Method("GET", "/health", http.HandlerFunc(adapter.HealthCheck)) r.Method("GET", "/users", http.HandlerFunc(adapter.ListUsers)) r.Method("POST", "/users", http.HandlerFunc(adapter.CreateUser)) diff --git a/examples/server/test/echo/testcase/adapter.gen.go b/examples/server/test/echo/testcase/adapter.gen.go index 04c18efc..e2873420 100644 --- a/examples/server/test/echo/testcase/adapter.gen.go +++ b/examples/server/test/echo/testcase/adapter.gen.go @@ -140,8 +140,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -150,7 +151,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -268,7 +269,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1339,7 +1340,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1392,7 +1393,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1440,8 +1441,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []echo.MiddlewareFunc - errHandler OapiErrorHandler + middlewares []echo.MiddlewareFunc + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1459,6 +1461,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter registers routes on the given Echo instance with the service implementation. func NewRouter(e *echo.Echo, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -1472,6 +1482,9 @@ func NewRouter(e *echo.Echo, svc ServiceInterface, opts ...RouterOption) { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } e.GET("/health", func(c echo.Context) error { adapter.HealthCheck(c.Response(), c.Request()) return nil diff --git a/examples/server/test/fasthttp/testcase/adapter.gen.go b/examples/server/test/fasthttp/testcase/adapter.gen.go index 4fd4b815..90b97057 100644 --- a/examples/server/test/fasthttp/testcase/adapter.gen.go +++ b/examples/server/test/fasthttp/testcase/adapter.gen.go @@ -142,8 +142,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -152,7 +153,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -270,7 +271,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1341,7 +1342,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1394,7 +1395,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1442,8 +1443,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(fasthttp.RequestHandler) fasthttp.RequestHandler - errHandler OapiErrorHandler + middlewares []func(fasthttp.RequestHandler) fasthttp.RequestHandler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1461,6 +1463,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // fasthttpHandler wraps an http.HandlerFunc with path param injection for fasthttp. func fasthttpHandler(h http.HandlerFunc, pathParams ...string) fasthttp.RequestHandler { return func(ctx *fasthttp.RequestCtx) { @@ -1487,6 +1497,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) *router.Router { r := router.New() httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.GET("/health", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.HealthCheck)) r.GET("/users", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.ListUsers)) r.POST("/users", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.CreateUser)) @@ -1537,6 +1550,9 @@ func Handler(svc ServiceInterface, opts ...RouterOption) fasthttp.RequestHandler r := router.New() httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.GET("/health", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.HealthCheck)) r.GET("/users", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.ListUsers)) r.POST("/users", fasthttpadaptor.NewFastHTTPHandlerFunc(httpAdapter.CreateUser)) diff --git a/examples/server/test/fiber/testcase/adapter.gen.go b/examples/server/test/fiber/testcase/adapter.gen.go index 38884f36..bdff3a9e 100644 --- a/examples/server/test/fiber/testcase/adapter.gen.go +++ b/examples/server/test/fiber/testcase/adapter.gen.go @@ -141,8 +141,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -151,7 +152,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -269,7 +270,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1340,7 +1341,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1393,7 +1394,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1441,8 +1442,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []fiber.Handler - errHandler OapiErrorHandler + middlewares []fiber.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1460,6 +1462,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // fiberHTTPHandler wraps an http.HandlerFunc with path param injection for Fiber. func fiberHTTPHandler(h http.HandlerFunc, pathParams ...string) fiber.Handler { return func(c fiber.Ctx) error { @@ -1486,6 +1496,9 @@ func NewRouter(app *fiber.App, svc ServiceInterface, opts ...RouterOption) { } httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } app.Get("/health", adaptor.HTTPHandlerFunc(httpAdapter.HealthCheck)) app.Get("/users", adaptor.HTTPHandlerFunc(httpAdapter.ListUsers)) app.Post("/users", adaptor.HTTPHandlerFunc(httpAdapter.CreateUser)) diff --git a/examples/server/test/gin/testcase/adapter.gen.go b/examples/server/test/gin/testcase/adapter.gen.go index 72eebad9..e1c2d18d 100644 --- a/examples/server/test/gin/testcase/adapter.gen.go +++ b/examples/server/test/gin/testcase/adapter.gen.go @@ -140,8 +140,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -150,7 +151,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -268,7 +269,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1339,7 +1340,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1392,7 +1393,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1440,8 +1441,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []gin.HandlerFunc - errHandler OapiErrorHandler + middlewares []gin.HandlerFunc + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1459,6 +1461,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter registers routes on the given Gin engine with the service implementation. func NewRouter(r *gin.Engine, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -1472,6 +1482,9 @@ func NewRouter(r *gin.Engine, svc ServiceInterface, opts ...RouterOption) { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.GET("/health", func(c *gin.Context) { adapter.HealthCheck(c.Writer, c.Request) }) diff --git a/examples/server/test/go-zero/testcase/adapter.gen.go b/examples/server/test/go-zero/testcase/adapter.gen.go index ea8a8044..4e14c5ea 100644 --- a/examples/server/test/go-zero/testcase/adapter.gen.go +++ b/examples/server/test/go-zero/testcase/adapter.gen.go @@ -142,8 +142,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -152,7 +153,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -270,7 +271,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1341,7 +1342,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1394,7 +1395,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1442,8 +1443,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []rest.Middleware - errHandler OapiErrorHandler + middlewares []rest.Middleware + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1461,6 +1463,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // RegisterRoutes registers all routes with the given go-zero server. func RegisterRoutes(server *rest.Server, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -1469,6 +1479,9 @@ func RegisterRoutes(server *rest.Server, svc ServiceInterface, opts ...RouterOpt } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } routes := []rest.Route{ { @@ -1607,6 +1620,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) http.Handler { r := router.NewRouter() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } _ = r.Handle("GET", "/health", http.HandlerFunc(adapter.HealthCheck)) _ = r.Handle("GET", "/users", http.HandlerFunc(adapter.ListUsers)) _ = r.Handle("POST", "/users", http.HandlerFunc(adapter.CreateUser)) diff --git a/examples/server/test/goframe/testcase/adapter.gen.go b/examples/server/test/goframe/testcase/adapter.gen.go index 215dc78b..3a586d09 100644 --- a/examples/server/test/goframe/testcase/adapter.gen.go +++ b/examples/server/test/goframe/testcase/adapter.gen.go @@ -140,8 +140,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -150,7 +151,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -268,7 +269,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1339,7 +1340,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1392,7 +1393,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1440,8 +1441,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []ghttp.HandlerFunc - errHandler OapiErrorHandler + middlewares []ghttp.HandlerFunc + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1459,6 +1461,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter registers routes on the given GoFrame server with the service implementation. func NewRouter(s *ghttp.Server, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -1472,6 +1482,9 @@ func NewRouter(s *ghttp.Server, svc ServiceInterface, opts ...RouterOption) { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } s.BindHandler("GET:/health", func(r *ghttp.Request) { adapter.HealthCheck(r.Response.Writer, r.Request) }) @@ -1572,6 +1585,9 @@ func Handler(svc ServiceInterface, opts ...RouterOption) http.Handler { mux := http.NewServeMux() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } mux.HandleFunc("GET /health", adapter.HealthCheck) mux.HandleFunc("GET /users", adapter.ListUsers) mux.HandleFunc("POST /users", adapter.CreateUser) diff --git a/examples/server/test/gorilla-mux/testcase/adapter.gen.go b/examples/server/test/gorilla-mux/testcase/adapter.gen.go index 09dcbd8a..94dcd9d6 100644 --- a/examples/server/test/gorilla-mux/testcase/adapter.gen.go +++ b/examples/server/test/gorilla-mux/testcase/adapter.gen.go @@ -140,8 +140,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -150,7 +151,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -268,7 +269,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1339,7 +1340,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1392,7 +1393,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1440,8 +1441,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []mux.MiddlewareFunc - errHandler OapiErrorHandler + middlewares []mux.MiddlewareFunc + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1459,6 +1461,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new mux.Router with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) *mux.Router { cfg := &routerConfig{} @@ -1472,6 +1482,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) *mux.Router { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.HandleFunc("/health", adapter.HealthCheck).Methods("GET") r.HandleFunc("/users", adapter.ListUsers).Methods("GET") r.HandleFunc("/users", adapter.CreateUser).Methods("POST") diff --git a/examples/server/test/hertz/testcase/adapter.gen.go b/examples/server/test/hertz/testcase/adapter.gen.go index dce514ed..9180d524 100644 --- a/examples/server/test/hertz/testcase/adapter.gen.go +++ b/examples/server/test/hertz/testcase/adapter.gen.go @@ -143,8 +143,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -153,7 +154,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -271,7 +272,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1342,7 +1343,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1395,7 +1396,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1443,8 +1444,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []app.HandlerFunc - errHandler OapiErrorHandler + middlewares []app.HandlerFunc + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1462,6 +1464,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter registers routes on the given Hertz server with the service implementation. func NewRouter(h *server.Hertz, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -1475,6 +1485,9 @@ func NewRouter(h *server.Hertz, svc ServiceInterface, opts ...RouterOption) { } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } h.Handle("GET", "/health", func(ctx context.Context, c *app.RequestContext) { req, err := adaptor.GetCompatRequest(&c.Request) if err != nil { @@ -1713,6 +1726,9 @@ func Handler(svc ServiceInterface, opts ...RouterOption) http.Handler { mux := http.NewServeMux() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } mux.HandleFunc("GET /health", adapter.HealthCheck) mux.HandleFunc("GET /users", adapter.ListUsers) mux.HandleFunc("POST /users", adapter.CreateUser) diff --git a/examples/server/test/iris/testcase/adapter.gen.go b/examples/server/test/iris/testcase/adapter.gen.go index ac6a61ff..1b987d70 100644 --- a/examples/server/test/iris/testcase/adapter.gen.go +++ b/examples/server/test/iris/testcase/adapter.gen.go @@ -140,8 +140,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -150,7 +151,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -268,7 +269,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1339,7 +1340,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1392,7 +1393,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1440,8 +1441,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []iris.Handler - errHandler OapiErrorHandler + middlewares []iris.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1459,6 +1461,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter registers routes on the given Iris application with the service implementation. func NewRouter(app *iris.Application, svc ServiceInterface, opts ...RouterOption) { cfg := &routerConfig{} @@ -1472,6 +1482,9 @@ func NewRouter(app *iris.Application, svc ServiceInterface, opts ...RouterOption } adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } app.Handle("GET", "/health", func(ctx iris.Context) { adapter.HealthCheck(ctx.ResponseWriter(), ctx.Request()) }) @@ -1572,6 +1585,9 @@ func Handler(svc ServiceInterface, opts ...RouterOption) http.Handler { mux := http.NewServeMux() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } mux.HandleFunc("GET /health", adapter.HealthCheck) mux.HandleFunc("GET /users", adapter.ListUsers) mux.HandleFunc("POST /users", adapter.CreateUser) diff --git a/examples/server/test/kratos/testcase/adapter.gen.go b/examples/server/test/kratos/testcase/adapter.gen.go index 177843f4..79a48ec9 100644 --- a/examples/server/test/kratos/testcase/adapter.gen.go +++ b/examples/server/test/kratos/testcase/adapter.gen.go @@ -141,8 +141,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -151,7 +152,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -269,7 +270,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1340,7 +1341,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1393,7 +1394,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1441,8 +1442,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1460,6 +1462,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // RegisterRoutes registers all routes with the given Kratos HTTP server. // It creates a gorilla/mux router and mounts it using HandlePrefix. func RegisterRoutes(server *kratoshttp.Server, svc ServiceInterface, opts ...RouterOption) { @@ -1478,6 +1488,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) http.Handler { r := mux.NewRouter() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } r.HandleFunc("/health", adapter.HealthCheck).Methods("GET") r.HandleFunc("/users", adapter.ListUsers).Methods("GET") r.HandleFunc("/users", adapter.CreateUser).Methods("POST") diff --git a/examples/server/test/server_test.go b/examples/server/test/server_test.go index 48267b7c..da677263 100644 --- a/examples/server/test/server_test.go +++ b/examples/server/test/server_test.go @@ -24,6 +24,7 @@ import ( irisapi "github.com/doordash-oss/oapi-codegen-dd/v3/examples/server/test/iris/testcase" kratosapi "github.com/doordash-oss/oapi-codegen-dd/v3/examples/server/test/kratos/testcase" stdhttpapi "github.com/doordash-oss/oapi-codegen-dd/v3/examples/server/test/std-http/testcase" + "github.com/doordash-oss/oapi-codegen-dd/v3/pkg/runtime" "github.com/gin-gonic/gin" "github.com/gofiber/fiber/v3" iris "github.com/kataras/iris/v12" @@ -458,3 +459,52 @@ func TestGetItemsByStatus_TypeAndRatingPathParams(t *testing.T) { }) } } + +func TestWithJSONBodyDecoder(t *testing.T) { + t.Run("custom decoder is called for JSON body", func(t *testing.T) { + var called bool + mux := stdhttpapi.NewRouter(stdhttpapi.NewService(), + stdhttpapi.WithJSONBodyDecoder(func(body io.Reader, target any) error { + called = true + return runtime.DecodeJSONBody(body, target) + }), + ) + + reqBody := `{"name": "Alice", "email": "alice@example.com"}` + req := httptest.NewRequest("POST", "/users", strings.NewReader(reqBody)) + req.Header.Set("Content-Type", "application/json") + resp, err := httpHandler{mux}.Do(req) + require.NoError(t, err) + defer func() { _ = resp.Body.Close() }() + + assert.True(t, called, "custom body decoder should have been called") + assert.Equal(t, http.StatusCreated, resp.StatusCode) + }) + + t.Run("custom decoder can transform the body", func(t *testing.T) { + mux := stdhttpapi.NewRouter(stdhttpapi.NewService(), + stdhttpapi.WithJSONBodyDecoder(func(body io.Reader, target any) error { + data, err := io.ReadAll(body) + if err != nil { + return err + } + modified := strings.Replace(string(data), "Original", "Transformed", 1) + return runtime.DecodeJSONBody(strings.NewReader(modified), target) + }), + ) + + reqBody := `{"name": "Original", "email": "test@example.com"}` + req := httptest.NewRequest("POST", "/users", strings.NewReader(reqBody)) + req.Header.Set("Content-Type", "application/json") + resp, err := httpHandler{mux}.Do(req) + require.NoError(t, err) + defer func() { _ = resp.Body.Close() }() + + assert.Equal(t, http.StatusCreated, resp.StatusCode) + + var user map[string]any + err = json.NewDecoder(resp.Body).Decode(&user) + require.NoError(t, err) + assert.Equal(t, "Transformed", user["name"]) + }) +} diff --git a/examples/server/test/std-http/testcase/adapter.gen.go b/examples/server/test/std-http/testcase/adapter.gen.go index 1a10ad99..6d149268 100644 --- a/examples/server/test/std-http/testcase/adapter.gen.go +++ b/examples/server/test/std-http/testcase/adapter.gen.go @@ -139,8 +139,9 @@ type ServiceInterface interface { // HTTPAdapter adapts the ServiceInterface to HTTP handlers. // This struct is generated and should not be modified. type HTTPAdapter struct { - svc ServiceInterface - errHandler OapiErrorHandler + svc ServiceInterface + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -149,7 +150,7 @@ func NewHTTPAdapter(svc ServiceInterface, errHandler OapiErrorHandler) *HTTPAdap if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } // HealthCheck handles GET /health @@ -267,7 +268,7 @@ func (a *HTTPAdapter) CreateUser(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateUserBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateUser", @@ -1338,7 +1339,7 @@ func (a *HTTPAdapter) CreateOrder(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateOrderBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateOrder", @@ -1391,7 +1392,7 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { // Parse request body defer r.Body.Close() var body CreateCompanyBody - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { a.errHandler.HandleError(w, r, http.StatusBadRequest, OapiHandlerError{ Kind: OapiErrorKindDecode, OperationID: "CreateCompany", @@ -1439,8 +1440,9 @@ func (a *HTTPAdapter) CreateCompany(w http.ResponseWriter, r *http.Request) { type RouterOption func(*routerConfig) type routerConfig struct { - middlewares []func(http.Handler) http.Handler - errHandler OapiErrorHandler + middlewares []func(http.Handler) http.Handler + errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -1458,6 +1460,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // NewRouter creates a new http.ServeMux with the given service implementation. func NewRouter(svc ServiceInterface, opts ...RouterOption) *http.ServeMux { cfg := &routerConfig{} @@ -1468,6 +1478,9 @@ func NewRouter(svc ServiceInterface, opts ...RouterOption) *http.ServeMux { mux := http.NewServeMux() adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } mux.HandleFunc("GET /health", applyMiddleware(http.HandlerFunc(adapter.HealthCheck), cfg.middlewares...)) mux.HandleFunc("GET /users", applyMiddleware(http.HandlerFunc(adapter.ListUsers), cfg.middlewares...)) mux.HandleFunc("POST /users", applyMiddleware(http.HandlerFunc(adapter.CreateUser), cfg.middlewares...)) diff --git a/pkg/codegen/templates/handler/adapter.tmpl b/pkg/codegen/templates/handler/adapter.tmpl index e32a3844..3f731822 100644 --- a/pkg/codegen/templates/handler/adapter.tmpl +++ b/pkg/codegen/templates/handler/adapter.tmpl @@ -39,6 +39,7 @@ type {{ $serviceName }}Interface interface { type HTTPAdapter struct { svc {{ $serviceName }}Interface errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // NewHTTPAdapter creates a new HTTPAdapter wrapping the given service. @@ -47,7 +48,7 @@ func NewHTTPAdapter(svc {{ $serviceName }}Interface, errHandler OapiErrorHandler if errHandler == nil { errHandler = &OapiDefaultErrorHandler{} } - return &HTTPAdapter{svc: svc, errHandler: errHandler} + return &HTTPAdapter{svc: svc, errHandler: errHandler, jsonBodyDecoder: runtime.DecodeJSONBody} } {{define "handle-validation-error"}} @@ -331,7 +332,7 @@ func (a *HTTPAdapter) {{ $op.ID | ucFirst }}(w http.ResponseWriter, r *http.Requ defer r.Body.Close() {{- if or (eq $op.Body.ContentType "application/json") (hasSuffix $op.Body.ContentType "+json") }} var body {{ $op.Body.Name }} - if err := runtime.DecodeJSONBody(r.Body, &body); err != nil { + if err := a.jsonBodyDecoder(r.Body, &body); err != nil { {{- if $hasTypedError }} a.errHandler.HandleError(w, r, {{ $op.Response.Error.StatusCode }}, New{{ $errorTypeName }}(err.Error())) {{- else }} diff --git a/pkg/codegen/templates/handler/beego/handler.tmpl b/pkg/codegen/templates/handler/beego/handler.tmpl index b8b25c6b..32c917c0 100644 --- a/pkg/codegen/templates/handler/beego/handler.tmpl +++ b/pkg/codegen/templates/handler/beego/handler.tmpl @@ -28,6 +28,7 @@ beecontext "github.com/beego/beego/v2/server/web/context"{{end}} type routerConfig struct { middlewares []beego.MiddleWare errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -45,6 +46,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // beegoHandler wraps an http.HandlerFunc for Beego with path param injection. func beegoHandler(h http.HandlerFunc, pathParams ...string) beego.HandleFunc { return func(ctx *beecontext.Context) { @@ -72,6 +81,9 @@ func RegisterRoutes(router *beego.ControllerRegister, svc {{ $serviceName }}Inte {{- if $operations }} httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} router.{{ $op.Method | lower | ucFirst }}("{{template "router-path" $op.Path}}", beegoHandler(httpAdapter.{{ $op.ID | ucFirst }}{{ if $op.PathParams }}{{ range $op.PathParams.Schema.Properties }}, "{{ .JsonFieldName }}"{{ end }}{{ end }})) {{- end }} diff --git a/pkg/codegen/templates/handler/chi/handler.tmpl b/pkg/codegen/templates/handler/chi/handler.tmpl index eb4f2f1d..09eca8d1 100644 --- a/pkg/codegen/templates/handler/chi/handler.tmpl +++ b/pkg/codegen/templates/handler/chi/handler.tmpl @@ -26,6 +26,7 @@ limitations under the License. type routerConfig struct { middlewares []func(http.Handler) http.Handler errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -42,6 +43,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { cfg.errHandler = h } } + +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} {{end}} {{define "new-router"}} @@ -63,6 +72,9 @@ func NewRouter(svc {{ $serviceName }}Interface, opts ...RouterOption) chi.Router {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} r.Method("{{ $op.Method }}", "{{template "router-path" $op.Path}}", http.HandlerFunc(adapter.{{ $op.ID | ucFirst }})) {{- end }} diff --git a/pkg/codegen/templates/handler/echo/handler.tmpl b/pkg/codegen/templates/handler/echo/handler.tmpl index b99fc97e..56c59d31 100644 --- a/pkg/codegen/templates/handler/echo/handler.tmpl +++ b/pkg/codegen/templates/handler/echo/handler.tmpl @@ -27,6 +27,7 @@ limitations under the License. type routerConfig struct { middlewares []echo.MiddlewareFunc errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -43,6 +44,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { cfg.errHandler = h } } + +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} {{end}} {{define "new-router"}} @@ -64,6 +73,9 @@ func NewRouter(e *echo.Echo, svc {{ $serviceName }}Interface, opts ...RouterOpti {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} e.{{ $op.Method | caps }}("{{template "router-path" $op.Path}}", func(c echo.Context) error { {{- if $op.PathParams }} diff --git a/pkg/codegen/templates/handler/fasthttp/handler.tmpl b/pkg/codegen/templates/handler/fasthttp/handler.tmpl index 6b53b773..100068a4 100644 --- a/pkg/codegen/templates/handler/fasthttp/handler.tmpl +++ b/pkg/codegen/templates/handler/fasthttp/handler.tmpl @@ -29,6 +29,7 @@ limitations under the License. type routerConfig struct { middlewares []func(fasthttp.RequestHandler) fasthttp.RequestHandler errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -46,6 +47,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // fasthttpHandler wraps an http.HandlerFunc with path param injection for fasthttp. func fasthttpHandler(h http.HandlerFunc, pathParams ...string) fasthttp.RequestHandler { return func(ctx *fasthttp.RequestCtx) { @@ -79,6 +88,9 @@ func NewRouter(svc {{ $serviceName }}Interface, opts ...RouterOption) *router.Ro {{- if $operations }} httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} {{- if $op.PathParams }} r.{{ $op.Method }}("{{template "router-path" $op.Path}}", fasthttpHandler(httpAdapter.{{ $op.ID | ucFirst }}{{ range $op.PathParams.Schema.Properties }}, "{{ .JsonFieldName }}"{{ end }})) @@ -118,6 +130,9 @@ func Handler(svc {{ $serviceName }}Interface, opts ...RouterOption) fasthttp.Req {{- if $operations }} httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} {{- if $op.PathParams }} r.{{ $op.Method }}("{{ $op.Path }}", fasthttpHandler(httpAdapter.{{ $op.ID | ucFirst }}{{ range $op.PathParams.Schema.Properties }}, "{{ .JsonFieldName }}"{{ end }})) diff --git a/pkg/codegen/templates/handler/fiber/handler.tmpl b/pkg/codegen/templates/handler/fiber/handler.tmpl index fac503be..accf48f2 100644 --- a/pkg/codegen/templates/handler/fiber/handler.tmpl +++ b/pkg/codegen/templates/handler/fiber/handler.tmpl @@ -28,6 +28,7 @@ limitations under the License. type routerConfig struct { middlewares []fiber.Handler errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -45,6 +46,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { } } +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} + // fiberHTTPHandler wraps an http.HandlerFunc with path param injection for Fiber. func fiberHTTPHandler(h http.HandlerFunc, pathParams ...string) fiber.Handler { return func(c fiber.Ctx) error { @@ -78,6 +87,9 @@ func NewRouter(app *fiber.App, svc {{ $serviceName }}Interface, opts ...RouterOp {{- if $operations }} httpAdapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + httpAdapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} {{- if $op.PathParams }} app.{{ $op.Method | lower | ucFirst }}("{{template "router-path" $op.Path}}", fiberHTTPHandler(httpAdapter.{{ $op.ID | ucFirst }}{{ range $op.PathParams.Schema.Properties }}, "{{ .JsonFieldName }}"{{ end }})) diff --git a/pkg/codegen/templates/handler/gin/handler.tmpl b/pkg/codegen/templates/handler/gin/handler.tmpl index 4fc6bbd6..a651c6e2 100644 --- a/pkg/codegen/templates/handler/gin/handler.tmpl +++ b/pkg/codegen/templates/handler/gin/handler.tmpl @@ -27,6 +27,7 @@ limitations under the License. type routerConfig struct { middlewares []gin.HandlerFunc errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -43,6 +44,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { cfg.errHandler = h } } + +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} {{end}} {{define "new-router"}} @@ -64,6 +73,9 @@ func NewRouter(r *gin.Engine, svc {{ $serviceName }}Interface, opts ...RouterOpt {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} r.{{ $op.Method | caps }}("{{template "router-path" $op.Path}}", func(c *gin.Context) { {{- if $op.PathParams }} diff --git a/pkg/codegen/templates/handler/go-zero/handler.tmpl b/pkg/codegen/templates/handler/go-zero/handler.tmpl index 43bc8143..bef65221 100644 --- a/pkg/codegen/templates/handler/go-zero/handler.tmpl +++ b/pkg/codegen/templates/handler/go-zero/handler.tmpl @@ -28,6 +28,7 @@ limitations under the License. type routerConfig struct { middlewares []rest.Middleware errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -44,6 +45,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { cfg.errHandler = h } } + +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} {{end}} {{define "new-router"}} @@ -60,6 +69,9 @@ func RegisterRoutes(server *rest.Server, svc {{ $serviceName }}Interface, opts . {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } routes := []rest.Route{ {{- range $operations }}{{ $op := . }} @@ -95,6 +107,9 @@ func NewRouter(svc {{ $serviceName }}Interface, opts ...RouterOption) http.Handl {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} _ = r.Handle("{{ $op.Method }}", "{{template "router-path" $op.Path}}", http.HandlerFunc(adapter.{{ $op.ID | ucFirst }})) {{- end }} diff --git a/pkg/codegen/templates/handler/goframe/handler.tmpl b/pkg/codegen/templates/handler/goframe/handler.tmpl index 813fa39e..1c9374ab 100644 --- a/pkg/codegen/templates/handler/goframe/handler.tmpl +++ b/pkg/codegen/templates/handler/goframe/handler.tmpl @@ -27,6 +27,7 @@ limitations under the License. type routerConfig struct { middlewares []ghttp.HandlerFunc errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -43,6 +44,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { cfg.errHandler = h } } + +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} {{end}} {{define "new-router"}} @@ -64,6 +73,9 @@ func NewRouter(s *ghttp.Server, svc {{ $serviceName }}Interface, opts ...RouterO {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} s.BindHandler("{{ $op.Method | caps }}:{{template "router-path" $op.Path}}", func(r *ghttp.Request) { {{- if $op.PathParams }} @@ -93,6 +105,9 @@ func Handler(svc {{ $serviceName }}Interface, opts ...RouterOption) http.Handler {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} mux.HandleFunc("{{ $op.Method | caps }} {{ $op.Path }}", adapter.{{ $op.ID | ucFirst }}) {{- end }} diff --git a/pkg/codegen/templates/handler/gorilla-mux/handler.tmpl b/pkg/codegen/templates/handler/gorilla-mux/handler.tmpl index 8fae91ba..f60172bd 100644 --- a/pkg/codegen/templates/handler/gorilla-mux/handler.tmpl +++ b/pkg/codegen/templates/handler/gorilla-mux/handler.tmpl @@ -26,6 +26,7 @@ limitations under the License. type routerConfig struct { middlewares []mux.MiddlewareFunc errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -42,6 +43,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { cfg.errHandler = h } } + +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} {{end}} {{define "new-router"}} @@ -63,6 +72,9 @@ func NewRouter(svc {{ $serviceName }}Interface, opts ...RouterOption) *mux.Route {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} r.HandleFunc("{{template "router-path" $op.Path}}", adapter.{{ $op.ID | ucFirst }}).Methods("{{ $op.Method }}") {{- end }} diff --git a/pkg/codegen/templates/handler/hertz/handler.tmpl b/pkg/codegen/templates/handler/hertz/handler.tmpl index 43a059a5..ae74818f 100644 --- a/pkg/codegen/templates/handler/hertz/handler.tmpl +++ b/pkg/codegen/templates/handler/hertz/handler.tmpl @@ -31,6 +31,7 @@ limitations under the License. type routerConfig struct { middlewares []app.HandlerFunc errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -47,6 +48,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { cfg.errHandler = h } } + +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} {{end}} {{define "new-router"}} @@ -68,6 +77,9 @@ func NewRouter(h *server.Hertz, svc {{ $serviceName }}Interface, opts ...RouterO {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} h.Handle("{{ $op.Method | caps }}", "{{template "router-path" $op.Path}}", func(ctx context.Context, c *app.RequestContext) { req, err := adaptor.GetCompatRequest(&c.Request) @@ -103,6 +115,9 @@ func Handler(svc {{ $serviceName }}Interface, opts ...RouterOption) http.Handler {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} mux.HandleFunc("{{ $op.Method | caps }} {{ $op.Path }}", adapter.{{ $op.ID | ucFirst }}) {{- end }} diff --git a/pkg/codegen/templates/handler/iris/handler.tmpl b/pkg/codegen/templates/handler/iris/handler.tmpl index fa363a82..66cb090c 100644 --- a/pkg/codegen/templates/handler/iris/handler.tmpl +++ b/pkg/codegen/templates/handler/iris/handler.tmpl @@ -27,6 +27,7 @@ limitations under the License. type routerConfig struct { middlewares []iris.Handler errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -43,6 +44,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { cfg.errHandler = h } } + +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} {{end}} {{define "new-router"}} @@ -64,6 +73,9 @@ func NewRouter(app *iris.Application, svc {{ $serviceName }}Interface, opts ...R {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} app.Handle("{{ $op.Method | caps }}", "{{template "router-path" $op.Path}}", func(ctx iris.Context) { {{- if $op.PathParams }} @@ -93,6 +105,9 @@ func Handler(svc {{ $serviceName }}Interface, opts ...RouterOption) http.Handler {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} mux.HandleFunc("{{ $op.Method | caps }} {{ escapeGoString $op.Path }}", adapter.{{ $op.ID | ucFirst }}) {{- end }} diff --git a/pkg/codegen/templates/handler/kratos/handler.tmpl b/pkg/codegen/templates/handler/kratos/handler.tmpl index 7d2a5dc4..724d3475 100644 --- a/pkg/codegen/templates/handler/kratos/handler.tmpl +++ b/pkg/codegen/templates/handler/kratos/handler.tmpl @@ -27,6 +27,7 @@ limitations under the License. type routerConfig struct { middlewares []func(http.Handler) http.Handler errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -43,6 +44,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { cfg.errHandler = h } } + +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} {{end}} {{define "new-router"}} @@ -69,6 +78,9 @@ func NewRouter(svc {{ $serviceName }}Interface, opts ...RouterOption) http.Handl {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} r.HandleFunc("{{template "router-path" $op.Path}}", adapter.{{ $op.ID | ucFirst }}).Methods("{{ $op.Method }}") {{- end }} diff --git a/pkg/codegen/templates/handler/std-http/handler.tmpl b/pkg/codegen/templates/handler/std-http/handler.tmpl index 38c8f9e1..a1337227 100644 --- a/pkg/codegen/templates/handler/std-http/handler.tmpl +++ b/pkg/codegen/templates/handler/std-http/handler.tmpl @@ -26,6 +26,7 @@ limitations under the License. type routerConfig struct { middlewares []func(http.Handler) http.Handler errHandler OapiErrorHandler + jsonBodyDecoder runtime.JSONBodyDecoderFunc } // WithMiddleware adds middleware to the router. @@ -42,6 +43,14 @@ func WithErrorHandler(h OapiErrorHandler) RouterOption { cfg.errHandler = h } } + +// WithJSONBodyDecoder sets a custom function for decoding JSON request bodies. +// If not set, runtime.DecodeJSONBody is used. +func WithJSONBodyDecoder(fn runtime.JSONBodyDecoderFunc) RouterOption { + return func(cfg *routerConfig) { + cfg.jsonBodyDecoder = fn + } +} {{end}} {{define "new-router"}} @@ -60,6 +69,9 @@ func NewRouter(svc {{ $serviceName }}Interface, opts ...RouterOption) *http.Serv {{- if $operations }} adapter := NewHTTPAdapter(svc, cfg.errHandler) + if cfg.jsonBodyDecoder != nil { + adapter.jsonBodyDecoder = cfg.jsonBodyDecoder + } {{- range $operations }}{{ $op := . }} mux.HandleFunc("{{ $op.Method }} {{template "router-path" $op.Path}}", applyMiddleware(http.HandlerFunc(adapter.{{ $op.ID | ucFirst }}), cfg.middlewares...)) {{- end }} diff --git a/pkg/runtime/json.go b/pkg/runtime/json.go index e0ae4e3b..4b2739f7 100644 --- a/pkg/runtime/json.go +++ b/pkg/runtime/json.go @@ -213,6 +213,10 @@ func UnmarshalAs[T any](v json.RawMessage) (T, error) { return res, err } +// JSONBodyDecoderFunc decodes a request body into the target value. +// The default implementation is DecodeJSONBody. +type JSONBodyDecoderFunc func(body io.Reader, target any) error + // DecodeJSONBody decodes a JSON request body into the target value. // It wraps common JSON decoding errors with user-friendly messages: // - io.EOF or empty body -> "request body is empty"