liveBook · Manning

Handler

As explained in Go by Example

A handler is a software component that receives an operation or request and produces the corresponding processing result.

An HTTP event handler receives a request and writes the corresponding response. In Go, a handler works with an http.ResponseWriter for output and an *http.Request for input. A minimal health handler can write "OK"; writing the body implicitly produces HTTP 200 unless WriteHeader set another status first. section 8.3.1

The http.Handler interface lets a server invoke request-processing behavior through ServeHTTP. http.HandlerFunc adapts an ordinary function with the handler signature into that interface, so ListenAndServe can call the function for every incoming request. section 8.3.2

Listing 8.10 Shorten handler (link/rest/shortener.go)
package rest

import (
    "fmt"
    "log/slog"
    "net/http"
    "github.com/inancgumus/gobyexample/link"
)

// Shorten returns an [http.Handler] that shortens URLs.
func Shorten(
    lg *slog.Logger, links *link.Shortener,  #1
) http.Handler {  #2
    return http.HandlerFunc(func(  #3
        w http.ResponseWriter, r *http.Request,   #3
    ) {   #3
        key, err := links.Shorten(r.Context(), link.Link{
            Key: link.Key(  #4
                r.PostFormValue("key"),   #4
            ),   #4
            URL: r.PostFormValue("url"),   #4
        })
        if err != nil {
            httpError(w, r, lg, fmt.Errorf(  #5
                "shortening: %w", err,  #5
            ))   #5
            return  #6
        }

        w.WriteHeader(http.StatusCreated)  #7
        fmt.Fprint(w, key)   #7
    })
}

A handler factory can take explicit dependencies and return a closure. The returned handler reads POST form values, calls a Shortener, stops immediately after an error response, or writes 201 Created and the generated key. section 8.4.1

Build handlers around a few practical rules:

  • Take dependencies as parameters rather than globals, making required collaborators visible and replaceable during tests. section 8.4.1
  • After writing an error response, return immediately to prevent duplicate operations, inconsistent responses, or unintended side effects. section 8.4.1
  • Register handlers on a ServeMux by route and method; the server sends incoming requests through the mux before a matching handler receives them. section 8.5.2
  • Test a handler directly with httptest.NewRequest and httptest.NewRecorder, then assert the captured status code and response body. section 8.7.2 section 8.8.2

Health endpoint

A health endpoint can be a plain function: func Health(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "OK") }. Register it with mux.HandleFunc("/health", rest.Health), or convert it explicitly with http.HandlerFunc(Health) when an http.Handler is required. Its simple 200/OK response lets load balancers and orchestrators monitor availability. section 8.3.1 section 8.3.2 section 8.5.2

Handlers remain easy to test when production and test code share the same HTTP types. httptest supplies requests, response recorders, and isolated servers that work with http.Request, http.ResponseWriter, http.Server, and http.Handler rather than test-only mocks. section 8.8.2

How Go by Example covers it

How deep it goes
Explains function adaptation, closures, status responses, routing, and direct tests, while deferring middleware composition.
Examples
Uses an OK health endpoint, a URL-shortening POST handler, ServeMux routes, and a ResponseRecorder-based test.
What you can do after
Apply it via Go’s net/http and httptest packages to register, test, and compose request handlers with explicit dependencies.
How it connects
Connects http.Handler with http.HandlerFunc, ServeMux, ResponseWriter, Request, closures, dependency injection, and httptest.

Also explained in

Compare how 22 books explain handler →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go by Example. The section links point to the parts of the book it draws on.