dependency injection: func (...<T>) iris.Handler can be generated to a simple iris handler if <T> are static dependencies

This commit is contained in:
Gerasimos (Makis) Maropoulos 2021-06-10 21:16:00 +03:00
parent 8f9140b705
commit 96c2dec47f
No known key found for this signature in database
GPG Key ID: ACAB76DFB0DD3F3B
6 changed files with 58 additions and 7 deletions

View File

@ -933,7 +933,7 @@ type (
// } // }
// Usage with (static) dependencies: // Usage with (static) dependencies:
// app.RegisterDependency(userRepo, ...) // app.RegisterDependency(userRepo, ...)
// app.PartyConfigure("/users", &api.UsersAPI{}) // app.PartyConfigure("/users", new(api.UsersAPI))
func (api *APIBuilder) PartyConfigure(relativePath string, partyReg ...PartyConfigurator) Party { func (api *APIBuilder) PartyConfigure(relativePath string, partyReg ...PartyConfigurator) Party {
var child Party var child Party

View File

@ -1059,12 +1059,10 @@ func cacheFiles(ctx stdContext.Context, fs http.FileSystem, names []string, comp
// so, unless requested keep it as it's. // so, unless requested keep it as it's.
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
for _, alg := range compressAlgs { for _, alg := range compressAlgs {
// stop all compressions if at least one file failed to.
select { select {
case <-ctx.Done(): case <-ctx.Done():
return ctx.Err() return ctx.Err() // stop all compressions if at least one file failed to.
default: default:
break // lint:ignore
} }
if alg == "brotli" { if alg == "brotli" {

View File

@ -347,6 +347,17 @@ func getBindingsForStruct(v reflect.Value, dependencies []*Dependency, markExpor
return return
} }
func getStaticInputs(bindings []*binding, numIn int) []reflect.Value {
inputs := make([]reflect.Value, numIn)
for _, b := range bindings {
if d := b.Dependency; d != nil && d.Static {
inputs[b.Input.Index], _ = d.Handle(nil, nil)
}
}
return inputs
}
/* /*
Builtin dynamic bindings. Builtin dynamic bindings.
*/ */

View File

@ -315,6 +315,26 @@ func Handler(fn interface{}) context.Handler {
// custom structs, Result(View | Response) and more. // custom structs, Result(View | Response) and more.
// It returns a standard `iris/context.Handler` which can be used anywhere in an Iris Application, // It returns a standard `iris/context.Handler` which can be used anywhere in an Iris Application,
// as middleware or as simple route handler or subdomain's handler. // as middleware or as simple route handler or subdomain's handler.
//
// func(...<T>) iris.Handler
// - if <T> are all static dependencies then
// there is no reflection involved at serve-time.
//
// func(pathParameter string, ...<T>)
// - one or more path parameters (e.g. :uid, :string, :int, :path, :uint64)
// are automatically binded to the first input Go standard types (string, int, uint64 and e.t.c.)
//
// func(<T>) error
// - if a function returns an error then this error's text is sent to the client automatically.
//
// func(<T>) <R>
// - The result of the function is a dependency too.
// If <R> is a request-scope dependency (dynamic) then
// this function will be called at every request.
//
// func(<T>) <R>
// - If <R> is static dependency (e.g. a database or a service) then its result
// can be used as a static dependency to the next dependencies or to the controller/function itself.
func (c *Container) Handler(fn interface{}) context.Handler { func (c *Container) Handler(fn interface{}) context.Handler {
return c.HandlerWithParams(fn, 0) return c.HandlerWithParams(fn, 0)
} }

View File

@ -454,11 +454,10 @@ func (r Response) Dispatch(ctx *context.Context) {
ctx.SetLanguage(r.Lang) ctx.SetLanguage(r.Lang)
r.Content = []byte(ctx.Tr(r.Text, r.Object)) r.Content = []byte(ctx.Tr(r.Text, r.Object))
return } else {
}
r.Content = []byte(r.Text) r.Content = []byte(r.Text)
} }
}
err := dispatchCommon(ctx, r.Code, r.ContentType, r.Content, r.Object, defaultResultHandler, true) err := dispatchCommon(ctx, r.Code, r.ContentType, r.Content, r.Object, defaultResultHandler, true)
dispatchErr(ctx, r.Code, err) dispatchErr(ctx, r.Code, err)

View File

@ -84,6 +84,15 @@ var (
}) })
) )
var (
irisHandlerType = reflect.TypeOf((*context.Handler)(nil)).Elem()
irisHandlerFuncType = reflect.TypeOf(func(*context.Context) {})
)
func isIrisHandlerType(typ reflect.Type) bool {
return typ == irisHandlerType || typ == irisHandlerFuncType
}
func makeHandler(fn interface{}, c *Container, paramsCount int) context.Handler { func makeHandler(fn interface{}, c *Container, paramsCount int) context.Handler {
if fn == nil { if fn == nil {
panic("makeHandler: function is nil") panic("makeHandler: function is nil")
@ -110,6 +119,20 @@ func makeHandler(fn interface{}, c *Container, paramsCount int) context.Handler
bindings := getBindingsForFunc(v, c.Dependencies, c.DisablePayloadAutoBinding, paramsCount) bindings := getBindingsForFunc(v, c.Dependencies, c.DisablePayloadAutoBinding, paramsCount)
c.fillReport(context.HandlerName(fn), bindings) c.fillReport(context.HandlerName(fn), bindings)
// Check if it's a function that accept zero or more dependencies
// and returns an Iris Handler.
if paramsCount <= 0 {
// println(irisHandlerType.String())
if typ.NumOut() == 1 && isIrisHandlerType(typ.Out(0)) {
inputs := getStaticInputs(bindings, numIn)
if len(inputs) != numIn {
panic(fmt.Sprintf("makeHandler: func(...<T>) iris.Handler: expected %d function input parameters but fewer static dependencies matched (%d)", numIn, len(inputs)))
}
handler := v.Call(inputs)[0].Interface().(context.Handler)
return handler
}
}
resultHandler := defaultResultHandler resultHandler := defaultResultHandler
for i, lidx := 0, len(c.resultHandlers)-1; i <= lidx; i++ { for i, lidx := 0, len(c.resultHandlers)-1; i <= lidx; i++ {
resultHandler = c.resultHandlers[lidx-i](resultHandler) resultHandler = c.resultHandlers[lidx-i](resultHandler)