Documentation ¶
Overview ¶
Package scaffolder is a dependency injection framework dedicated into abstracting the redundant boilerplate needed to build any Golang application and letting you build what you want to build without having to rewrite yet another /health endpoint.
Example ¶
package main import ( "context" "log" "math/rand" "net/http" "time" "github.com/Vorian-Atreides/scaffolder" "github.com/Vorian-Atreides/scaffolder/application" "github.com/Vorian-Atreides/scaffolder/component/healthcheck" ) type SomeComponent struct { HealthRegistry healthcheck.HealthRegistry } func (s *SomeComponent) Start(ctx context.Context) error { for { i := rand.Intn(4) select { case <-ctx.Done(): return nil case <-time.After(time.Duration(i) * time.Second): } a.HealthRegistry.SetStatus("SomeComponent", healthcheck.Status(i)) } return nil } type Server struct { Readiness *healthcheck.HTTPHandler `scaffolder:"readiness"` Liveness *healthcheck.HTTPHandler `scaffolder:"liveness"` } func (s *Server) Start(ctx context.Context) error { mux := http.DefaultServeMux mux.Handle("/ready", s.Readiness) mux.Handle("/healthy", s.Liveness) server := http.Server{ Addr: ":8080", Handler: mux, } server.ListenAndServe() return nil } func main() { app, err := application.New( application.WithComponent(healthcheck.NewRegistry()), application.WithComponent(&SomeComponent{}), application.WithComponent( &healthcheck.HTTPHandler{}, scaffolder.WithName("readiness"), ), application.WithComponent( &healthcheck.HTTPHandler{}, healthcheck.WithMergingStrategy( healthcheck.EveryService(healthcheck.Healthy, healthcheck.NotReady), ), scaffolder.WithName("liveness"), ), application.WithComponent(&Server{}), ) if err != nil { log.Fatal(err) } if err := app.Run(context.Background()); err != nil { log.Fatal(err) } }
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidTarget is returned if the target given in the Init function is not a pointer. ErrInvalidTarget = errors.New("the target must be a pointer") // ErrInvalidOption is returned if the given Option does not respect the prototype: // func(pointer) error. ErrInvalidOption = errors.New("the option does not respect the mandatory prototype") )
var ( // ErrInvalidComponent means that the given component was neither a pointer not an interface. ErrInvalidComponent = errors.New("component is neither a pointer nor an interface") )
Functions ¶
func Configure ¶
func Configure(target Component, cfg Configuration) error
Configure apply the Options returned by the Configuration.
type Config struct { FirstName string `json:"first_name"` Age int `json:"age"` } func (c *Config) Options() []scaffolder.Option { return []scaffolder.Option{ WithAge(c.Age), } }
func Init ¶
Init will take care of initializing the given Component by first calling the default method, if the component implements the Defaulter interface.
Afterward, it will iterate through the list of options and apply them one after another.
type Form struct { Age int FirstName string } func (f *Form) Default() { f.FirstName = "FirstName" } func WithAge(age int) scaffolder.Option { return func(f *Form) error { f.Age = age return nil } }
Types ¶
type Component ¶
type Component interface{}
Component let you define your application into small, independent, reusable element. Think of a component as a service or aggregate of structure and logic that you want to share with the rest of your code base or with other application.
Not everything is intended to be a component, but anything which would benefits from the scaffolder dependency injection, configuration or application life cycle should be thought as a component.
type Configuration ¶
type Configuration interface {
Options() []Option
}
Configuration define a generic interface to turn configuration structure into usable component in the Scaffolder framework.
type Defaulter ¶
type Defaulter interface {
Default()
}
Defaulter optional interface which can be used to attach default values to a component.
type Inventory ¶
type Inventory struct {
// contains filtered or unexported fields
}
Inventory define a registry of component where any component can resolve its dependencies. You can think of it as a bag of tools where the hammer will automatically goes next to the nails.
Currently the assignment algorithm follow this priority:
- The component name match the field tag.
- The component name and type match the field name and type (case sensitive).
- The component type match the field type.
- Component implements the field interface.
A valid assignable field must be a public and can be either a pointer, an interface or a slice. At the moment the slice is an experiments to build higher level components over the whole set of components.
Directories ¶
Path | Synopsis |
---|---|
Package application define a simple application life cycle which should be robust enough for most of the application or be extended by your own custom implementation if it does not.
|
Package application define a simple application life cycle which should be robust enough for most of the application or be extended by your own custom implementation if it does not. |
component
|
|
logger
Package logger define a Logger component which can be used to wrap the logger in your application.
|
Package logger define a Logger component which can be used to wrap the logger in your application. |
examples
|
|