diff --git a/HISTORY.md b/HISTORY.md index 4f3bfa01..113350c1 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -28,6 +28,8 @@ The codebase for Dependency Injection, Internationalization and localization and ## Fixes and Improvements +- Add `Party.EnsureStaticBindings` which, if called, the MVC binder panics if a struct's input binding depends on the HTTP request data instead of a static dependency. This is useful to make sure your API crafted through `Party.PartyConfigure` depends only on struct values you already defined at `Party.RegisterDependency` == will never use reflection at serve-time (maximum performance). + - Add a new [x/sqlx](/x/sqlx/) sub-package ([example](_examples/database/sqlx/main.go)). - Add a new [x/reflex](/x/reflex) sub-package. diff --git a/_examples/websocket/basic/README.md b/_examples/websocket/basic/README.md index 948b18bc..334c0ef9 100644 --- a/_examples/websocket/basic/README.md +++ b/_examples/websocket/basic/README.md @@ -16,6 +16,7 @@ This example contains only the basics, however, the library supports rooms, nati Open a terminal window instance and execute: ```sh +$ go mod tidy -compat=1.17 $ go run server.go # start the websocket server. ``` @@ -25,6 +26,7 @@ Start a new terminal instance and execute: ```sh $ cd ./go-client +$ go mod tidy -compat=1.17 $ go run client.go # start the websocket client. # start typing... ``` diff --git a/core/router/api_builder.go b/core/router/api_builder.go index 892c9117..aa220470 100644 --- a/core/router/api_builder.go +++ b/core/router/api_builder.go @@ -339,6 +339,15 @@ func (api *APIBuilder) ConfigureContainer(builder ...func(*APIContainer)) *APICo return api.apiBuilderDI } +// EnsureStaticBindings panics on struct handler (controller) +// if at least one input binding depends on the request and not in a static structure. +// Should be called before `RegisterDependency`. +func (api *APIBuilder) EnsureStaticBindings() Party { + diContainer := api.ConfigureContainer() + diContainer.Container.DisableStructDynamicBindings = true + return api +} + // RegisterDependency calls the `ConfigureContainer.RegisterDependency` method // with the provided value(s). See `HandleFunc` and `PartyConfigure` methods too. func (api *APIBuilder) RegisterDependency(dependencies ...interface{}) { diff --git a/core/router/party.go b/core/router/party.go index 0776010e..ab49432e 100644 --- a/core/router/party.go +++ b/core/router/party.go @@ -27,6 +27,10 @@ type Party interface { // // It returns the same `APIBuilder` featured with Dependency Injection. ConfigureContainer(builder ...func(*APIContainer)) *APIContainer + // EnsureStaticBindings panics on struct handler (controller) + // if at least one input binding depends on the request and not in a static structure. + // Should be called before `RegisterDependency`. + EnsureStaticBindings() Party // RegisterDependency calls the `ConfigureContainer.RegisterDependency` method // with the provided value(s). See `HandleFunc` and `PartyConfigure` methods too. RegisterDependency(dependencies ...interface{}) diff --git a/hero/container.go b/hero/container.go index 1e53d005..ee3e392c 100644 --- a/hero/container.go +++ b/hero/container.go @@ -53,6 +53,10 @@ type Container struct { // set to true to disable that kind of behavior. DisablePayloadAutoBinding bool + // DisableStructDynamicBindings if true panics on struct handler (controller) + // if at least one input binding depends on the request and not in a static structure. + DisableStructDynamicBindings bool + // DependencyMatcher holds the function that compares equality between // a dependency with an input. Defaults to DefaultMatchDependencyFunc. DependencyMatcher DependencyMatcher @@ -249,6 +253,7 @@ func (c *Container) Clone() *Container { copy(clonedDeps, c.Dependencies) cloned.Dependencies = clonedDeps cloned.DisablePayloadAutoBinding = c.DisablePayloadAutoBinding + cloned.DisableStructDynamicBindings = c.DisableStructDynamicBindings cloned.MarkExportedFieldsAsRequired = c.MarkExportedFieldsAsRequired cloned.resultHandlers = c.resultHandlers // Reports are not cloned. diff --git a/hero/struct.go b/hero/struct.go index 496463a9..ea2c5d72 100644 --- a/hero/struct.go +++ b/hero/struct.go @@ -71,6 +71,10 @@ func makeStruct(structPtr interface{}, c *Container, partyParamsCount int) *Stru elem.FieldByIndex(b.Input.StructFieldIndex).Set(input) } else if !b.Dependency.Static { + if c.DisableStructDynamicBindings { + panic(fmt.Sprintf("binder: DisableStructDynamicBindings setting is set to true: dynamic binding found: %s", b.String())) + } + singleton = false } }