A service is more than a handler function. Someone must configure it, bind a listener, observe serve errors and stop it. Make those responsibilities explicit before adding routes.
This course builds a small JSON notes API with Go’s standard library. You need Go packages/tests, JSON contracts and HTTP request/status fundamentals. Hosted exercises use recorders and open no sockets. The download includes the real loopback server.
The service is a local learning artifact: one process, bounded in-memory notes, no authentication or persistence. Its scope is visible so later storage and authorization work has a clear starting point.
The server value names an explicit handler instead of relying on DefaultServeMux. A nil handler is an error in this lab. Every call returns a fresh value so tests and independent instances do not share mutable configuration.
Bind only 127.0.0.1 and use port zero for an OS-assigned port. The command prints the actual URL. That avoids collisions and keeps the unauthenticated demonstration on the learner’s own machine.
package main
import ("fmt";"net/http";"time")
func main(){
h:=http.HandlerFunc(func(w http.ResponseWriter,r *http.Request){w.WriteHeader(202)})
s:=&http.Server{Addr:"127.0.0.1:0",Handler:h,ReadHeaderTimeout:2*time.Second}
fmt.Println(s.Addr,s.ReadHeaderTimeout)
}Timeout fields bound different stages. ReadHeaderTimeout covers header reading; ReadTimeout covers request reading; WriteTimeout and IdleTimeout have separate connection semantics. These finite teaching values are not universal production settings or a complete application deadline.
The local command starts Serve, watches cancellation or an early serve failure, and calls Shutdown with a five-second context. If graceful shutdown fails, it closes the server and joins the serve result. An ordinary ErrServerClosed is expected after shutdown. Other errors should reach the caller.
The hosted configuration exercise does none of that network work. It proves the handler and limits without binding a port, which preserves the existing playground boundary.
package main
import ("fmt";"context")
func main(){
ctx,cancel:=context.WithCancel(context.Background());defer cancel()
cancel();fmt.Println(ctx.Err())
}Complete the exact configuration contract and test nil handlers and independent instances. Keep listener creation out of the constructor.
Next we decide which method/path combinations the service actually supports, including the difference between 404 and 405.