Lab 11: HTTP & REST

Objective

Build HTTP clients and servers using Go's standard library net/http: GET/POST requests, JSON APIs, middleware, routing, and a complete REST server.

Time

35 minutes

Prerequisites

  • Lab 10 (File I/O & JSON)

Tools

  • Docker image: zchencow/innozverse-go:latest


Lab Instructions

Step 1: HTTP Client — GET Requests

docker run --rm zchencow/innozverse-go:latest go run - << 'EOF'
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "time"
)

type JSONPlaceholderPost struct {
    UserID int    `json:"userId"`
    ID     int    `json:"id"`
    Title  string `json:"title"`
    Body   string `json:"body"`
}

func main() {
    // Default client — fine for simple use
    client := &http.Client{Timeout: 10 * time.Second}

    resp, err := client.Get("https://jsonplaceholder.typicode.com/posts/1")
    if err != nil {
        // Fallback for offline environments
        fmt.Println("HTTP GET (offline, showing structure):")
        mock := JSONPlaceholderPost{1, 1, "sunt aut facere repellat", "quia et suscipit..."}
        data, _ := json.MarshalIndent(mock, "", "  ")
        fmt.Println(string(data))
        return
    }
    defer resp.Body.Close()

    fmt.Println("Status:", resp.Status)
    fmt.Println("Content-Type:", resp.Header.Get("Content-Type"))

    body, _ := io.ReadAll(resp.Body)
    var post JSONPlaceholderPost
    json.Unmarshal(body, &post)
    fmt.Printf("Post #%d by user %d:\n  %s\n", post.ID, post.UserID, post.Title)
}
EOF

💡 Always set a Timeout on your HTTP client — the default http.DefaultClient has no timeout, so a slow server can block your goroutine forever. Also always defer resp.Body.Close() — not closing it leaks the connection. Use io.ReadAll(resp.Body) to read the full response.

📸 Verified Output:


Step 2: HTTP Server with Standard Library

💡 net/http/httptest lets you test HTTP handlers without starting a real server. httptest.NewRequest + httptest.NewRecorder record the response. This is how the Go standard library tests its own HTTP code — fast, parallel, no port conflicts.

📸 Verified Output:


Steps 3–8: Middleware Chain, Request Parsing, Custom Router, Rate Limiter, Capstone REST API

📸 Verified Output:


Summary

Pattern
Code

HTTP GET

http.Get(url) or client.Do(req)

HTTP server

http.NewServeMux() + mux.HandleFunc()

JSON response

json.NewEncoder(w).Encode(v)

JSON request

json.NewDecoder(r.Body).Decode(&v)

Middleware

func(http.Handler) http.Handler

Testing

httptest.NewRequest + httptest.NewRecorder

Pattern routing

mux.HandleFunc("GET /path/{id}", fn) (Go 1.22)

Further Reading

Last updated