The Server Calls You
A Go web server is built from handlers: functions with the shape func(w http.ResponseWriter, r *http.Request). The server accepts connections and calls your handler once per request — r holds everything about the request, and whatever you write into w becomes the response.
A real server starts with http.ListenAndServe(":8080", mux) and runs forever. The examples here use httptest.NewServer instead — a real server on a random free port that the program can start, use and stop, so every example runs and finishes by itself.
A First Handler
The smallest possible handler writes a line of text. Everything an API does — JSON, status codes, routing — happens inside this same function shape.
Hello from a handler
The handler writes into w; the client reads exactly that as the response body, with status 200 OK filled in automatically.
Output: Go program and captured output
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "hello from the server")
}
func main() {
server := httptest.NewServer(http.HandlerFunc(hello))
defer server.Close()
resp, _ := http.Get(server.URL + "/")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println("status:", resp.Status)
fmt.Print("body: ", string(body))
}
Answering with JSON
An API handler does three things: set the Content-Type header, choose a status code, and encode the data. json.NewEncoder(w).Encode(value) writes JSON straight into the response.
Order matters: headers must be set before the body is written.
A JSON endpoint
The handler encodes a struct directly into the response writer. The client receives valid JSON and the right content type — this is the skeleton of every endpoint in the rest of this group.
Output: Go program and captured output
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func userHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(User{ID: 1, Name: "Ana"})
}
func main() {
server := httptest.NewServer(http.HandlerFunc(userHandler))
defer server.Close()
resp, _ := http.Get(server.URL + "/user")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println("status:", resp.Status)
fmt.Println("type: ", resp.Header.Get("Content-Type"))
fmt.Print("body: ", string(body))
}