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.ServeMux
will route requests received by the server to different handlers. To begin with, it will route requests sent to/echo
to*EchoHandler
, so its constructor should accept*EchoHandler
as 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
NewServeMux
was added aboveNewEchoHandler
--the order in which constructors are given tofx.Provide
does not matter. -
Lastly, modify the
NewHTTPServer
function 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.