Route Handlers
Register HTTP route handlers using generic method registration, REST-style shortcuts, and standard HTTP methods.
Route handlers define how the router responds to incoming HTTP requests.
The router supports two styles of handler registration:
- generic registration with
HandleFunc - method-specific shortcuts such as
GET,POST,PUT, andDELETE
All router-native handlers use the same signature:
func(w http.ResponseWriter, req *http.Request, ctx *router.Context)The additional *router.Context gives handlers access to route parameters and request-scoped storage.
Handler Registration Methods
| Method | Purpose |
|---|---|
HandleFunc(path, methods, handler) | Registers a handler for one or more HTTP methods |
GET(path, handler) | Registers a GET route |
POST(path, handler) | Registers a POST route |
PUT(path, handler) | Registers a PUT route |
PATCH(path, handler) | Registers a PATCH route |
DELETE(path, handler) | Registers a DELETE route |
HEAD(path, handler) | Registers a HEAD route |
OPTIONS(path, handler) | Registers an OPTIONS route |
TRACE(path, handler) | Registers a TRACE route |
CONNECT(path, handler) | Registers a CONNECT route |
Generic Handler Registration
Use HandleFunc when a route should accept multiple HTTP methods.
r.HandleFunc("/documents", "GET POST", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
if req.Method == http.MethodGet {
w.Write([]byte(`{"action": "Reading document list"}`))
return
}
if req.Method == http.MethodPost {
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"action": "Creating a new document"}`))
return
}
})Methods are passed as a space-separated string.
r.HandleFunc("/documents", "GET POST", handler)Use ANY to allow all supported methods.
r.HandleFunc("/any", "ANY", handler)Method Shortcuts
Use method-specific helpers for common REST-style APIs.
r.GET("/users/{id}", handler)
r.POST("/users", handler)
r.PUT("/users/{id}", handler)
r.PATCH("/users/{id}", handler)
r.DELETE("/users/{id}", handler)These shortcuts make route definitions easier to scan and keep API code explicit.
Example
package main
import (
"fmt"
"log/slog"
"net/http"
"os"
"github.com/netlifeguru/router"
)
func main() {
r := router.New()
r.UseDefaults()
r.HandleFunc("/any", "ANY", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"message": "This catches anything!", "used_method": "%s"}`, req.Method)
})
r.HandleFunc("/documents", "GET POST", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
w.Header().Set("Content-Type", "application/json")
if req.Method == http.MethodGet {
w.Write([]byte(`{"action": "Reading document list"}`))
return
}
if req.Method == http.MethodPost {
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"action": "Creating a new document"}`))
return
}
})
r.GET("/users/{id}", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
id := ctx.Param("id")
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"id": "%s", "name": "Alice"}`, id)
})
r.POST("/users", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"message": "User successfully created", "id": 3}`))
})
r.PUT("/users/{id:isDigits}", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
userID := ctx.Param("id")
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"message": "User %s has been completely updated"}`, userID)
})
r.PATCH("/users/{id:isDigits}", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
userID := ctx.Param("id")
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"message": "User %s has been partially updated"}`, userID)
})
r.DELETE("/users/{id:isDigits}", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
userID := ctx.Param("id")
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"message": "User %s has been deleted"}`, userID)
})
r.HEAD("/ping", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
w.Header().Set("X-System-Status", "Online")
w.Header().Set("Content-Length", "0")
w.WriteHeader(http.StatusOK)
})
r.OPTIONS("/api", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
w.Header().Set("Allow", "OPTIONS, GET, POST, PUT, DELETE")
w.WriteHeader(http.StatusNoContent)
})
r.TRACE("/echo", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
w.Header().Set("Content-Type", "message/http")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "%s %s %s\n", req.Method, req.URL.RequestURI(), req.Proto)
for name, headers := range req.Header {
for _, value := range headers {
fmt.Fprintf(w, "%s: %s\n", name, value)
}
}
})
r.CONNECT("/tunnel", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Tunnel connection established"))
})
if err := r.ListenAndServe(":8000"); err != nil {
slog.Error("failed to start server", "error", err)
os.Exit(1)
}
}
HTTP Method Usage
| Method | Common Use |
|---|---|
GET | Retrieve a resource |
POST | Create a new resource or submit data |
PUT | Replace an existing resource |
PATCH | Partially update an existing resource |
DELETE | Remove a resource |
HEAD | Retrieve headers without a response body |
OPTIONS | Discover supported methods or handle CORS preflight |
TRACE | Diagnostic request echoing |
CONNECT | Establish a tunnel, commonly used by proxies |
ANY | Accept all supported HTTP methods |
Route Parameters
Handlers can access route parameters through ctx.Param.
r.GET("/users/{id}", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
id := ctx.Param("id")
w.Write([]byte(id))
})Parameters can also be validated using route patterns:
r.GET("/users/{id:isDigits}", handler)Pattern-based routing is covered in the dedicated route patterns section.
Notes
Use HandleFunc when one route should support multiple methods.
Use method-specific helpers when each HTTP method has its own behavior.
For standard net/http handlers without *router.Context, use Mount or MountFunc.
Getting Started
Learn how to create your first HTTP server with the NLG Router package using static routes, parameterized routes, and middleware-ready handlers.
Parameterized Routes
Use route parameters, prepared pattern matchers, and custom regex constraints to validate URL segments before requests reach handlers.