Lección 19 · 19 de 20
Manejadores HTTP y httptest · Go
Escriba un manejador HTTP en Go con net/http que responde en JSON y pruébelo con httptest, sin red ni servidor. Así trabaja el destino Web (Go).

Un servidor web en Go es, sobre todo, un manejador: una función con la firma func(w http.ResponseWriter, r *http.Request). r trae la petición (método, ruta, parámetros) y en w se escribe la respuesta. En DMarlon Studio, Go es el servidor del destino Web (Go): las páginas de la aplicación piden datos a manejadores como este.
priceHandler lee el parámetro con r.URL.Query().Get("sku") y lo busca en prices. El switch decide la respuesta: si el método no es GET, `http.Error` escribe el código 405 y un texto; si el producto no existe, 404. Si no se indica ningún código, la respuesta sale con 200.
En el caso bueno, primero se fijan las cabeceras con w.Header().Set("Content-Type", "application/json") (después de escribir el cuerpo ya no se pueden cambiar) y luego json.NewEncoder(w).Encode(...) escribe el JSON directamente en la respuesta. Al ser un mapa, las claves salen en orden alfabético: price antes que sku.
`http.HandlerFunc(priceHandler)` convierte la función en un http.Handler, la interfaz que usa todo net/http. HandlerFunc es un tipo de función con un método ServeHTTP que llama a la propia función: interfaces y funciones como valores trabajando juntas.
Para probarlo no hace falta red. `httptest.NewRequest` construye una petición y `httptest.NewRecorder` es un ResponseWriter que guarda lo que se escribe: rec.Code, las cabeceras y rec.Body. Para servirlo de verdad bastaría con http.ListenAndServe(":8080", handler).
Código · main.go
package mainimport ( "encoding/json" "fmt" "net/http" "net/http/httptest")func priceHandler(w http.ResponseWriter, r *http.Request) { // GET /api/price?sku=... prices := map[string]float64{"KB-01": 49.9, "MS-02": 19.5} sku := r.URL.Query().Get("sku") price, ok := prices[sku] switch { case r.Method != http.MethodGet: http.Error(w, "method not allowed", http.StatusMethodNotAllowed) case !ok: http.Error(w, "unknown sku", http.StatusNotFound) default: w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(map[string]any{"sku": sku, "price": price}) }}func main() { handler := http.HandlerFunc(priceHandler) // the adapter that makes it an http.Handler requests := [][2]string{{"GET", "/api/price?sku=KB-01"}, {"GET", "/api/price?sku=ZZ-09"}, {"POST", "/api/price?sku=KB-01"}, {"GET", "/api/price?sku=MS-02"}} for _, req := range requests { rec := httptest.NewRecorder() // records status, headers and body: no network handler.ServeHTTP(rec, httptest.NewRequest(req[0], req[1], nil)) fmt.Printf("%-4s %-21s -> %d %s", req[0], req[1], rec.Code, rec.Body) }}Salida · go run main.go
GET /api/price?sku=KB-01 -> 200 {"price":49.9,"sku":"KB-01"}
GET /api/price?sku=ZZ-09 -> 404 unknown sku
POST /api/price?sku=KB-01 -> 405 method not allowed
GET /api/price?sku=MS-02 -> 200 {"price":19.5,"sku":"MS-02"}Para recordar
- Un manejador recibe un
http.ResponseWritery un*http.Request. http.Errorescribe un código de error y un texto.- Fije las cabeceras antes de escribir el cuerpo.
http.HandlerFuncconvierte una función en unhttp.Handler.httptestprueba manejadores sin red ni servidor.
Ejercicio
Haga que una petición sin sku (/api/price) responda 400 con el texto missing sku usando http.StatusBadRequest, y añádala a requests para comprobarlo.