Skip to content

Weekly Review — Month 4 · Week 1 (Days 085–091)

Journal index · Roadmap › this week

📅 The Week in One Line

Building real HTTP services with the standard library: the http.Handler interface, Go 1.22 routing, composable middleware, JSON helpers, and a graceful server lifecycle.

✅ What I Completed

  • Day 085 — http.Server + Go 1.22 ServeMux: methods, {id}/{path...}/{$}, auto 404/405
  • Day 086 — http.Handler interface & the HandlerFunc adapter
  • Day 087 — Routing with chi: sub-routers, regex params, route groups (snippet-only, third-party)
  • Day 088 — Middleware chains: func(http.Handler) http.Handler, Chain, RequestID/Logger/Recoverer
  • Day 089 — JSON request/response helpers: strict bounded decoding, uniform errors
  • Day 090 — Graceful shutdown & timeouts: Server.Shutdown, ErrServerClosed, signal.NotifyContext
  • Day 091 — Review + closed-book recall
  • Mini-project: a stdlib-only widgets API (servemux + middleware + JSON + graceful shutdown)
  • Exercises solved: 3 (respond, middleware, pathrouter) — all green, -race-clean

💡 Lessons Learned

  • The entire net/http ecosystem is one interface (ServeHTTP); everything else is wrappers and adapters around it.
  • Go 1.22's mux removed most reasons to reach for a router on small services — method routing, path wildcards, and automatic 405 are built in.
  • Middleware order is the whole game: Chain(A, B, C) makes A outermost, and Recoverer must sit near the top to catch inner panics (same-goroutine only).
  • Robust JSON decoding is mostly defensive flags: MaxBytesReader, DisallowUnknownFields, a dec.More() check, and mapping errors to 4xx codes.
  • http.ErrServerClosed is a success signal — treating it as fatal was the classic graceful-shutdown bug.

💪 Strengths (what clicked)

  • Reading path wildcards with r.PathValue instead of slicing URLs.
  • The func(http.Handler) http.Handler middleware shape and composing it.
  • Header-before-WriteHeader ordering and why the status freezes.

🧩 Weaknesses (what's still fuzzy)

  • Forwarding optional ResponseWriter interfaces (Flusher/Hijacker) through a wrapping middleware.
  • chi's NotFound/MethodNotAllowed customisation vs. the stdlib defaults.
  • Choosing sane timeout values for a given workload (needs real traffic shapes).

🔁 Spaced-Repetition Re-quiz (topics from earlier weeks)

  1. Q: (M1) What does string(65) produce and why?
    A"A" — int→rune to code point U+0041, not "65". Use strconv.Itoa.
  2. Q: (M2) What does %w in fmt.Errorf do?
    AWraps an error so errors.Is/errors.As can unwrap and match it.
  3. Q: (M3) Sending on a closed channel vs a nil channel?
    AClosed → panic; nil → blocks forever.
  4. Q: (M3) Why must context.Context be the first parameter?
    AConvention for cancellation/deadline propagation; tooling and readers expect ctx first.
  5. Q: (M4) Why use an unexported type for context keys?
    ASo your key can't collide with a key created in another package — value keys are compared by type and value.

🎯 Action Items

  • Add a status-capturing ResponseWriter wrapper that also forwards http.Flusher and test streaming.
  • Benchmark stdlib mux vs chi on a nested route tree to quantify the tradeoff.
  • Wire the Week 1 widgets API to a real datastore once Week 2 covers database/sql.

🚀 Next Week Goals

  • database/sql: DB, Conn, Stmt, Rows, QueryContext/ExecContext, connection pooling, context deadlines on queries.
  • Drivers (pgx) and code-gen (sqlc) at the concept level; repository pattern, migrations, and transactions modelled with the stdlib.
  • Pull the HTTP layer and the data layer together into a small REST service.

📊 Metrics

Hours Days hit Exercises Commits Avg confidence
9 7/7 3 7 3.⅗

Suggested commit: docs(journal): month 4 week 1 review