Register a handler¶
We built a server that can receive requests, but it doesn't yet know how to handle them. Let's fix that.
-
Define a basic HTTP handler that copies the incoming request body to the response. Add the following to the bottom of your file.
// EchoHandler is an http.Handler that copies its request body // back to the response. type EchoHandler struct{} // NewEchoHandler builds a new EchoHandler. func NewEchoHandler() *EchoHandler { return &EchoHandler{} } // ServeHTTP handles an HTTP request to the /echo endpoint. func (*EchoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if _, err := io.Copy(w, r.Body); err != nil { fmt.Fprintln(os.Stderr, "Failed to handle request:", err) } }Provide this to the application.
fx.Provide( NewHTTPServer, NewEchoHandler, ), fx.Invoke(func(*http.Server) {}), -
Next, write a function that builds an
*http.ServeMux. The*http.ServeMuxwill route requests received by the server to different handlers. To begin with, it will route requests sent to/echoto*EchoHandler, so its constructor should accept*EchoHandleras an argument.// NewServeMux builds a ServeMux that will route requests // to the given EchoHandler. func NewServeMux(echo *EchoHandler) *http.ServeMux { mux := http.NewServeMux() mux.Handle("/echo", echo) return mux }Likewise, provide this to the application.
fx.Provide( NewHTTPServer, NewServeMux, NewEchoHandler, ),Note that
NewServeMuxwas added aboveNewEchoHandler--the order in which constructors are given tofx.Providedoes not matter. -
Lastly, modify the
NewHTTPServerfunction to connect the server to this*ServeMux.func NewHTTPServer(lc fx.Lifecycle, mux *http.ServeMux) *http.Server { srv := &http.Server{Addr: ":8080", Handler: mux} lc.Append(fx.Hook{ -
Run the server.
[Fx] PROVIDE *http.Server <= main.NewHTTPServer() [Fx] PROVIDE *http.ServeMux <= main.NewServeMux() [Fx] PROVIDE *main.EchoHandler <= main.NewEchoHandler() [Fx] PROVIDE fx.Lifecycle <= go.uber.org/fx.New.func1() [Fx] PROVIDE fx.Shutdowner <= go.uber.org/fx.(*App).shutdowner-fm() [Fx] PROVIDE fx.DotGraph <= go.uber.org/fx.(*App).dotGraph-fm() [Fx] INVOKE main.main.func1() [Fx] HOOK OnStart main.NewHTTPServer.func1() executing (caller: main.NewHTTPServer) Starting HTTP server at :8080 [Fx] HOOK OnStart main.NewHTTPServer.func1() called by main.NewHTTPServer ran successfully in 7.459µs [Fx] RUNNING -
Send a request to the server.
$ curl -X POST -d 'hello' http://localhost:8080/echo hello
What did we just do?
We added more components with fx.Provide.
These components declared dependencies on each other
by adding parameters to their constructors.
Fx will resolve component dependencies by parameters and return values
of the provided functions.