Stage 1 · Code
Building Web Services
Routing and Middleware
Once one handler becomes five, structure matters. Learn how modern `ServeMux` patterns and middleware help a server stay organized without turning every handler into a kitchen sink.
When One Handler Becomes Many
A server with one route can get away with almost anything. You can hardcode the path, keep the logic in one file, and still stay sane. The trouble starts when the service grows. Suddenly you have a health check, a list endpoint, a detail endpoint, an admin area, and maybe a webhook. Without structure, every new route feels like adding one more cable to an already tangled desk.
Routing is the answer to the first problem: which handler should answer this request? Middleware is the answer to the second: how do we add shared behavior like logging, auth checks, or panic recovery without copying it into every handler? Think of routing as choosing the right room, and middleware as the building rules every room must follow.
A good handler focuses on the work unique to that endpoint. Cross-cutting behavior belongs outside it, wrapped around it, so the handler stays readable.
ServeMux Patterns in Go 1.22+
In older code you will often see switch r.URL.Path or a third-party router added very early. Go 1.22 made the standard ServeMux much more expressive. You can match on HTTP method and path in one pattern, and you can capture wildcard segments directly from the path.
| Route need | Pattern | How the handler reads data |
|---|---|---|
| Exact path | GET /healthz | No path values needed |
| Single wildcard | GET /articles/{slug} | r.PathValue("slug") |
| Nested wildcard | POST /teams/{teamID}/members/{memberID} | Read both path values by name |
| Method-specific route | DELETE /sessions/{id} | No manual if r.Method != ... check needed in the handler |
This does not magically turn a path into a database record. A path parameter is still just text. r.PathValue('slug') returns a string. Your handler decides what that string means, whether it is valid, and how to use it.
Middleware Wraps Handlers
Middleware is a function that takes a handler and returns a new handler. That sounds abstract until you picture a gift box. Your original handler is the present. Middleware is the wrapping paper that adds behavior around it before the box is opened and after it is closed.
That wrapper pattern is perfect for concerns that appear everywhere: logging request timings, checking authentication, attaching request IDs, enforcing rate limits, or recovering from panics so one bad request does not crash the whole server.
Wrapping order changes behavior. In this example, logging runs for every request, auth can stop unauthorized callers early, and recovery catches panics from deeper handlers before they crash the process.
Tracing a Request through the Chain
Let's walk one concrete request through the middleware stack. A client sends GET /admin/reports/panic with header X-Admin-Token: open-sesame. We choose the panic path value on purpose so you can see recovery happen.
GET /admin/reports/panic HTTP/1.1
Host: localhost:8080
X-Admin-Token: open-sesameThis is why middleware exists. The handler got to stay tiny and focused, while the surrounding chain handled operational behavior that every serious server needs.
Quiz and Practice
What does a path wildcard like `{reportID}` actually give your handler?
Hands-On Project
Write `requireHeader(name, value string) middleware`. The returned middleware must allow the request through only when the named header exactly matches the expected value. Otherwise it should return status `403` with body `forbidden`.
Summary and Key Takeaways
- Go 1.22+
ServeMuxpatterns can match method and path together, including wildcard segments. r.PathValue(...)gives you path text; handlers still own validation and meaning.- Middleware is a wrapper that adds shared behavior around a handler.
- Logging, auth checks, and panic recovery are classic middleware jobs because they cut across many endpoints.
- Middleware order affects request flow, so build chains deliberately instead of treating them like interchangeable stickers.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.