Request Lifecycle
Understand how an HTTP request moves through the router, from route matching and middleware execution to handler response and context cleanup.
The request lifecycle describes what happens when an HTTP request enters the router.
Understanding this flow helps when working with:
- middleware order
- request logging
- route parameters
- recovery handling
- request-scoped context
- response behavior
Lifecycle Overview
incoming HTTP request
↓
request context allocation
↓
route matching
↓
method validation
↓
middleware chain
↓
handler execution
↓
response writing
↓
panic recovery, if needed
↓
context cleanup1. Incoming Request
Every request starts as a standard Go HTTP request:
*http.RequestThe router is compatible with Go’s net/http ecosystem and can be used anywhere an http.Handler is expected.
2. Request Context
Before routing continues, the router prepares a request-scoped *router.Context.
This context is used for:
- route parameters
- temporary request values
- middleware-to-handler communication
func(w http.ResponseWriter, req *http.Request, ctx *router.Context)The context exists only for the lifetime of the request.
3. Route Matching
The router attempts to match the request path against registered routes.
It supports:
- static routes
- parameterized routes
- wildcard routes
- mounted handlers
- grouped routes
Example:
r.GET("/users/{id}", handler)Request:
GET /users/42Captured parameter:
id = 424. Method Validation
After the path is matched, the router validates the HTTP method.
Example:
r.HandleFunc("/documents", "GET POST", handler)Allowed methods:
GET
POSTIf the path exists but the method is not allowed, the router returns:
405 Method Not Allowed5. Middleware Execution
Before the handler runs, middleware is executed.
Middleware can be registered globally:
r.Use(router.RequestID())or on route groups:
api.Use(AuthMiddleware)Middleware can run logic before and after the next handler:
r.Use(func(next router.HandlerFunc) router.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
// before handler
next(w, req, ctx)
// after handler
}
})6. Handler Execution
If the route and method match, the final handler is executed.
r.GET("/users/{id}", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
id := ctx.Param("id")
w.Write([]byte(id))
})The handler can:
- read request data
- access route parameters
- read or write context values
- write headers
- write the response body
7. Response Writing
Handlers write responses using the standard http.ResponseWriter.
Example:
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"ok"}`))Because the router uses standard Go HTTP primitives, response behavior follows normal net/http rules.
8. Panic Recovery
If a handler panics, the router can recover and return a controlled response.
r.Recovery(func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("Internal Server Error"))
})If no custom recovery handler is configured, the router returns a standard internal server error response.
Recovered panics are logged through Go’s log/slog ecosystem.
9. Context Cleanup
After the request completes, the router releases the request context.
The context is reused internally to reduce allocations.
Applications should not store *router.Context beyond the request lifecycle.
Incorrect:
saved = ctxCorrect:
userID := ctx.Get("user_id")Copy the value you need instead of keeping the context itself.
Middleware Order
Middleware order is important.
Middleware is applied in the order it is registered:
r.Use(A)
r.Use(B)
r.Use(C)Execution flow:
A before
↓
B before
↓
C before
↓
handler
↓
C after
↓
B after
↓
A afterThis allows middleware to wrap behavior around later middleware and handlers.
Example Flow
For this route:
r.Use(router.RequestID())
r.Use(router.Logger())
r.GET("/users/{id}", handler)Request:
GET /users/42Lifecycle:
request received
↓
context prepared
↓
route /users/{id} matched
↓
id parameter extracted
↓
RequestID middleware runs
↓
Logger middleware starts timer
↓
handler executes
↓
Logger middleware writes request log
↓
context releasedNotes
The router keeps the request lifecycle explicit.
Routing, middleware, logging, recovery, and response writing remain separate concerns, making application behavior easier to understand, test, and debug.
Architecture
Understand how the router is structured internally, including route matching, middleware execution, context pooling, method matching, and standard library compatibility.
Graceful Shutdown
Gracefully stop HTTP servers, finish active requests, and safely release resources during application shutdown.