lunes, 27 de febrero de 2023

Inyección de dependencia en Go usando Fx


Vamos por parte, que es la inyección de dependencias?

Cualquier aplicación no trivial está formada por dos o más objetos que colaboran entre sí para realizar alguna lógica. Tradicionalmente cada objeto se hacía cargo de obtener sus propias referencias a los objetos a los cuales colaboraba (sus dependencias). Esto lleva a código acoplado y difícil de probar. Y para solucionar esto esta la inyección de dependencias. El contexto ingresa las dependencias de un objeto. Para mayor información pueden ir a : https://emanuelpeg.blogspot.com/2009/07/inyeccion-de-dependencias.html


Y que es Fx? Según la documentación oficial publicada por Uber, Fx es un framework para Go que:

  • Facilita la inyección de dependencia.
  • Elimina la necesidad de estado global y func init().

Fx usa el patrón de inyección de constructor, tratemos de entender exactamente cómo hace que la inyección de dependencia sea fácil en Go.

Para usar Fx debemos: 

El primer paso es instalar la biblioteca a través de go get go.uber.org/fx.

Y luego podemos hacer esto: 

package main


import (

"context"

"go.uber.org/fx"

"go.uber.org/fx/fxevent"

"log"

"net"

"net/http"

"os"

"time"

)


func NewLogger() *log.Logger {

logger := log.New(os.Stdout, "" /* prefix */, 0 /* flags */)

logger.Print("Create NewLogger.")

return logger

}


func NewHandler(logger *log.Logger) (http.Handler, error) {

logger.Print("Create NewHandler.")

return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {

logger.Print("Got a request.")

}), nil

}


func NewMux(lc fx.Lifecycle, logger *log.Logger) *http.ServeMux {

logger.Print("Create NewMux.")

mux := http.NewServeMux()

server := &http.Server{

Addr:    "127.0.0.1:8080",

Handler: mux,

}

lc.Append(fx.Hook{

OnStart: func(context.Context) error {

logger.Print("Starting HTTP server.")

ln, err := net.Listen("tcp", server.Addr)

if err != nil {

return err

}

go server.Serve(ln)

return nil

},

OnStop: func(ctx context.Context) error {

logger.Print("Stopping HTTP server.")

return server.Shutdown(ctx)

},

})


return mux

}


func Register(mux *http.ServeMux, h http.Handler) {

mux.Handle("/", h)

}


func main() {

app := fx.New(


fx.Provide(

NewLogger,

NewHandler,

NewMux,

),


fx.Invoke(Register),


fx.WithLogger(

func() fxevent.Logger {

return fxevent.NopLogger

},

),

)


startCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)

defer cancel()

if err := app.Start(startCtx); err != nil {

log.Fatal(err)

}


if _, err := http.Get("http://localhost:8080/"); err != nil {

log.Fatal(err)

}


stopCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second)

defer cancel()

if err := app.Stop(stopCtx); err != nil {

log.Fatal(err)

}


}


En el ejemplo queremos costruir varias entidades, un *log.Logger,  un http.Handler, un servidor *http.ServeMux y queremos llamar a una request. Y fx, nos construye estos objetos. 

Si ejecutamos esta aplicación el resultado será : 

Create NewLogger.
Create NewMux.
Create NewHandler.
Starting HTTP server.
Got a request.
Stopping HTTP server.


Dejo link: 


No hay comentarios.:

Publicar un comentario