Dependency Injection with fx

#Reading List

#Code

Code from Dependency Injection in Go using Fx Series series.

//  - config.yaml - 
//  - config.go - 
package main

type ApplicationConfig struct {
	Address string `yaml:"address"`
}

type Config struct {
	ApplicationConfig `yaml:"application"`
}
//  - main.go - 
package main

import (
	"bytes"
	"context"
	"io"
	"log"
	"net/http"
	"os"

	"github.com/butuzov/sandbox/dependency-injection/fx/httphandler"
	"go.uber.org/fx"
	"go.uber.org/zap"
	"gopkg.in/yaml.v3"
)

func main() {
	os.Exit(run())
}

func run() int {
	fx.New(
		fx.Provide(ProvideConfig),
		fx.Provide(ProvideLogger),
		fx.Provide(http.NewServeMux),
		fx.Provide(httphandler.New),
		// invokers
		fx.Invoke(registerHooks),
	).Run()

	return 0
}

func registerHooks(
	lifecycle fx.Lifecycle,
	logger *zap.SugaredLogger,
	cfg *Config,
	mux *httphandler.Handler,
) {
	lifecycle.Append(
		fx.Hook{
			OnStart: func(context.Context) error {
				go http.ListenAndServe(cfg.ApplicationConfig.Address, mux)
				return nil
			},
			OnStop: func(context.Context) error {
				return logger.Sync()
			},
		},
	)
}

func ProvideLogger() *zap.SugaredLogger {
	logger, _ := zap.NewProduction()
	slogger := logger.Sugar()

	return slogger
}

func ProvideConfig() *Config {
	var buf bytes.Buffer
	cnf := &Config{}

	f, err := os.Open("config.yaml")
	if err != nil {
		log.Printf("config: %s", err)
		return nil
	}

	defer f.Close()

	if _, err := io.Copy(&buf, f); err != nil {
		log.Printf("reading: %s", err)
		return nil
	}

	if err := yaml.Unmarshal(buf.Bytes(), &cnf); err != nil {
		log.Printf("yaml: %s", err)
		return nil
	}

	log.Printf("%#v", cnf)
	return cnf
}
//  - server.go - 
package httphandler

import (
	"net/http"

	"go.uber.org/zap"
)

// Handler for http requests
type Handler struct {
	mux *http.ServeMux
	log *zap.SugaredLogger
}

// RegisterRoutes for all http endpoints
func (h *Handler) registerRoutes() {
	h.mux.HandleFunc("/", h.hello)
}

func (h *Handler) hello(w http.ResponseWriter, r *http.Request) {
	h.log.Warn("request in")
	w.WriteHeader(200)
	w.Write([]byte("Hello World"))
	h.log.Warn("request out")
}

func New(s *http.ServeMux, l *zap.SugaredLogger) *Handler {
	h := Handler{s, l}
	h.registerRoutes()
	return &h
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.mux.ServeHTTP(w, r)
}