Go - Sample REST API
Beginner 10/10
Teacher 10/10
Architect 10/10
Overview
This capstone brings together HTTP routing, JSON encoding/decoding, context, logging, and a clean project layout. You can paste each file into your editor and run the service locally.
Project Layout
app/
cmd/api/main.go
internal/httpx/handlers.go
go.mod
go.mod
module example.com/app
go 1.22.0
require (
)
cmd/api/main.go
package main
import (
"log"
"net/http"
"os"
"time"
"example.com/app/internal/httpx"
)
func main(){
mux := http.NewServeMux()
mux.HandleFunc("/health", httpx.Health)
mux.HandleFunc("/echo", httpx.Echo)
srv := &http.Server{
Addr: ":8080",
Handler: logRequests(mux),
ReadHeaderTimeout: 5 * time.Second,
}
log.Println("listening on", srv.Addr)
if err := srv.ListenAndServe(); err != nil {
log.Println("server error:", err)
os.Exit(1)
}
}
func logRequests(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %s", r.Method, r.URL.Path, time.Since(start))
})
}
internal/httpx/handlers.go
package httpx
import (
"encoding/json"
"net/http"
"time"
"strings"
)
type Health struct{ Status string `json:"status"`; Time time.Time `json:"time"` }
type EchoReq struct{ Message string `json:"message"` }
type EchoResp struct{ Upper string `json:"upper"` }
func Health(w http.ResponseWriter, r *http.Request){
w.Header().Set("Content-Type","application/json")
_ = json.NewEncoder(w).Encode(Health{Status:"ok", Time: time.Now()})
}
func Echo(w http.ResponseWriter, r *http.Request){
if r.Method != http.MethodPost { http.Error(w, "method not allowed", http.StatusMethodNotAllowed); return }
var req EchoReq
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "bad json", http.StatusBadRequest); return
}
resp := EchoResp{ Upper: strings.ToUpper(req.Message) }
w.Header().Set("Content-Type","application/json")
_ = json.NewEncoder(w).Encode(resp)
}
Run
go run ./cmd/api
# in another terminal
curl -s localhost:8080/health | jq
curl -s -X POST localhost:8080/echo -d '{"message":"hello"}' -H 'Content-Type: application/json' | jq
Exercises
- Add request ID middleware. Return the ID in responses.
- Validate Echo input: reject empty messages with 422.
- Add /time endpoint that supports ?zone=UTC or local time.
Testing and Linting
go test ./...
go vet ./...
# optional if installed
golangci-lint run
Makefile (optional)
build:
go build -o bin/api ./cmd/api
test:
go test ./...
lint:
go vet ./...
golangci-lint run || true
run:
go run ./cmd/api