Runtime error-free dependency injection for Golang callbacks.
Use cases
Fetching values from contexts can lead to runtime errors that can only be tracked when you invoke the callback.
bar := req.Context.Value("foo").(barType) // panic: interface conversion: interface is fooType, not barType
Maintaining huge value objects and sharing it via some package global variable can be insecure, because everyone has access to its attributes and even can change it not intentionally.
package config var Config = ConfigVO{} type ConfigVO struct { DBConn *sql.DB Logger *log.Logger PaymentConfig *payment.Config // etc. }
Instead you declare only resources your callback needs, even if a callback has invalid arguments program panics at boot-up process decreasing amount of error-prone code:
dbConn := sql.Open("localhost:5432") logger := log.New(os.Stderr, "", LstdFlags) httpinject.With(handlerFoo, dbConn) httpinject.With(handlerBar, logger, dbConn) httpinject.With(handlerBaz, logger, dbConn) // panics, handlerBaz accepts log.Logger by value httpinject.With(handlerBam, logger, dbConn) // panics, handlerBam doesn't accept any extra arguments func handlerFoo(http.ResponseWriter, *http.Request, *sql.DB) {} func handlerBar(http.ResponseWriter, *http.Request, *log.Logger, *sql.DB) {} func handlerBaz(http.ResponseWriter, *http.Request, log.Logger, *sql.DB) {} func handlerBam(http.ResponseWriter, *http.Request) {}
Usage
net/http
package main import ( "fmt" httpinject "github.com/amenzhinsky/inject/http" "net/http" ) func main() { http.HandleFunc("/", httpinject.With(handler, 1, "foo")) http.ListenAndServe(":8080", nil) } func handler(w http.ResponseWriter, _ *http.Request, a int, s string) { w.WriteHeader(http.StatusOK) fmt.Fprintf(w, "a: %d, s: %s\n", a, s) }
Custom usage
Let's say with the echo webserver.
package main import ( "fmt" "github.com/amenzhinsky/inject" "github.com/labstack/echo" "github.com/labstack/echo/engine/standard" "net/http" "reflect" ) var typ = reflect.TypeOf((*echo.HandlerFunc)(nil)).Elem() func main() { e := echo.New() e.GET("/", with(handler, "Mr. President")) e.Run(standard.New(":8080")) } func handler(c echo.Context, name string) error { return c.String(http.StatusOK, fmt.Sprintf("Hello %s!\n", name)) } func with(fn interface{}, v ...interface{}) echo.HandlerFunc { return inject.With(typ, fn, v...).Interface().(echo.HandlerFunc) }