Step 01 of 06
Learn the concept
A service without an API is a batch job with opinions. Operators need to ask what Beacon knows while it is running. Go's standard net/http is enough, including method-and-pattern routing added in Go 1.22.
The ideas this is made of
A handler is a boundary object
http.HandlerFunc receives a request and a response writer. Everything inside is boundary work: parse parameters, call application code, map errors, encode output. Keeping this layer thin prevents HTTP concerns from leaking into storage or scheduling packages.
ServeMux now understands methods
In Go 1.22, mux.HandleFunc("GET /v1/results", handler) can match both method and path. That removes a common manual if r.Method != ... block and makes the routing table read like the API. Older prefix behaviour still exists, so be precise.
Middleware wraps policy around handlers
Middleware is a function that takes a handler and returns a handler. Logging, request IDs, timeouts and panic recovery fit here because they apply across routes. Business logic does not. If middleware needs to know what a target is, it has probably wandered too far inside.
Status codes are part of the contract
If a query parameter is invalid, return 400. If the route does not exist, let the mux return 404. If storage fails, return 503 or 500 based on the cause. Do not inherit 200 OK by writing a body first and thinking later; headers are sent once.
package main
import (
"fmt"
"net/http"
"net/http/httptest"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /hello/{name}", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, r.PathValue("name"))
})
r := httptest.NewRequest("GET", "/hello/sre", nil)
w := httptest.NewRecorder()
mux.ServeHTTP(w, r)
fmt.Println(w.Code, w.Body.String())
}The path variable comes from the mux, not a third-party router. Beacon can stay on the standard library and still have readable routes.
Common status choices
| Case | Code | Reason |
|---|---|---|
Bad limit | 400 | Client can fix input |
No route | 404 | Resource absent |
Wrong method | 405 | Method not allowed |
Store down | 503 | Dependency unavailable |
Bug | 500 | Unexpected server fault |
What these are called on the job
Handler — Code that turns one HTTP request into one HTTP response.
Middleware — A wrapper adding cross-cutting HTTP behaviour around handlers.
ServeMux — Go's request multiplexer for matching routes to handlers.
