Go Tutorial · Standard Library · Lesson 28 of 30
Go HTTP Server
Build a small JSON API with net/http — no framework needed.
A JSON API in the standard library
Go's net/http is production-grade. Since Go 1.22, routes can include methods and path parameters:
package main
import (
"encoding/json"
"log"
"net/http"
)
type Todo struct {
ID string `json:"id"`
Title string `json:"title"`
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /todos/{id}", func(w http.ResponseWriter, r *http.Request) {
todo := Todo{ID: r.PathValue("id"), Title: "Learn Go"}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(todo)
})
mux.HandleFunc("POST /todos", func(w http.ResponseWriter, r *http.Request) {
var t Todo
if err := json.NewDecoder(r.Body).Decode(&t); err != nil {
http.Error(w, "invalid JSON", http.StatusBadRequest)
return
}
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(t)
})
log.Println("listening on :8080")
log.Fatal(http.ListenAndServe(":8080", mux))
}
go run .
curl localhost:8080/todos/42
Each request runs in its own goroutine. Use r.Context() to stop work when the client disconnects, and set timeouts on an http.Server in production.
Testing handlers
net/http/httptest lets you call a handler without a network:
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.Fprintf(w, "Hello, %s!", r.PathValue("name"))
})
req := httptest.NewRequest("GET", "/hello/gopher", nil)
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, req)
fmt.Println(rec.Code, rec.Body.String())
rec = httptest.NewRecorder()
mux.ServeHTTP(rec, httptest.NewRequest("POST", "/hello/gopher", nil))
fmt.Println(rec.Code)
}
Output
200 Hello, gopher! 405
Run this on your computer — see “Get Started” for setup.
Test yourself
Since Go 1.22, how do you read the {id} path parameter in a handler?
r.Param("id")r.PathValue("id")mux.Vars(r)["id"]r.URL.Query().Get("id")
Show answer
Answer: r.PathValue("id")