Quick reference for common tasks in Mux.
go get github.com/fgrzl/muximport (
"context"
"os"
"os/signal"
"syscall"
"github.com/fgrzl/mux"
)
router := mux.NewRouter()
if err := router.Configure(func(router *mux.Router) {
router.GET("/health", healthHandler)
}); err != nil { panic(err) }
server := mux.NewServer(":8080", router)
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer cancel()
if err := server.Listen(ctx); err != nil { panic(err) }router := mux.NewRouter()
server := mux.NewServer(":9090", router)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if err := server.Start(ctx); err != nil { panic(err) }server := mux.NewServer(":8443", router,
mux.WithTLS("server.crt", "server.key"),
)
if err := server.Listen(ctx); err != nil { panic(err) }router.GET("/path", handler)
router.POST("/path", handler)
router.PUT("/path", handler)
router.DELETE("/path", handler)
router.PATCH("/path", handler)router.GET("/users/{id}", func(c mux.RouteContext) {
id, _ := c.Params().String("id")
c.OK(map[string]string{"userId": id})
})router.GET("/search", func(c mux.RouteContext) {
query := c.Query()
term, ok := query.String("q") // Single value
values, _ := query.Strings("tag") // Repeated values: ?tag=a&tag=b
if !ok {
c.BadRequest("Missing query", "q parameter is required")
return
}
c.OK(map[string]any{"q": term, "tags": values})
})router.GET("/files/*", handler) // Single-segment wildcard
router.GET("/static/**", handler) // Multi-segment catch-allapi := router.Group("/api/v1")
users := api.Group("/users")
users.GET("/", listUsers)
users.POST("/", createUsers)var data MyStruct
if err := c.Bind(&data); err != nil {
c.BadRequest("Invalid request", err.Error())
return
}token, ok := c.Headers().String("Authorization")
contentType, ok := c.Headers().String("Content-Type")sessionID, err := c.Cookies().Get("session_id")
if err != nil {
c.BadRequest("Missing cookie", err.Error())
return
}method := c.Request().Method
path := c.Request().URL.Pathc.OK(data) // 200 OK
c.Created(data) // 201 Created
c.NoContent() // 204 No Contentc.BadRequest("Invalid input", "describe the validation error") // 400
c.Unauthorized() // 401
c.Forbidden("Access denied") // 403
c.NotFound() // 404
c.Conflict("Resource already exists", "describe the conflict") // 409
c.ServerError("Error occurred", detail) // 500c.JSON(http.StatusCreated, data)
c.Plain(http.StatusTeapot, []byte("short and stout"))c.Response().Header().Set("X-Custom", "value")c.Cookies().Set("session", "abc123", 3600, "/", "", true, true)mux.UseLogging(router)
mux.UseCompression(router)
mux.UseCORS(router, mux.WithCORSAllowedOrigins("*"))
mux.UseRateLimiter(router)// Middleware is installed on the router.
// Use route-group defaults to mark public or protected areas.
public := router.Group("/public")
public.AllowAnonymous()
admin := router.Group("/admin")
admin.RequireRoles("admin")func MyMiddleware(c mux.MutableRouteContext, next mux.HandlerFunc) {
// Before handler
next(c)
// After handler
}
router.Use(mux.MiddlewareFunc(MyMiddleware))mux.UseAuthentication(router,
mux.WithAuthValidator(func(token string) (claims.Principal, error) {
// Validate token and return a principal.
claimSet := claims.NewClaimsSet("user-123")
return claims.NewPrincipal(claimSet), nil
}),
)user := c.User()
if user != nil {
subject := user.Subject()
_ = subject
}mux.UseAuthentication(router,
mux.WithAuthValidator(validateToken),
mux.WithAuthTokenCreator(createToken),
mux.WithAuthCSRFProtection(),
)
// Use c.Cookies().SignIn(...) to issue the framework-managed session cookie.router.GET("/users/{id}", getUser).
WithOperationID("getUser").
WithSummary("Get user by ID").
WithDescription("Returns a single user").
WithPathParam("id", "The unique user identifier", "user-123").
WithOKResponse(User{}).
WithResponse(404, mux.ProblemDetails{})
// With query parameters
router.GET("/search", searchUsers).
WithOperationID("searchUsers").
WithQueryParam("q", "Search query", "john"). // Optional query param
WithRequiredQueryParam("limit", "Maximum number of results", 10). // Required query param
WithOKResponse([]User{})
// With header parameter
router.GET("/data", getData).
WithHeaderParam("X-API-Version", "The API version", "v1").
WithOKResponse(map[string]any{})
// Low-level (if needed)
router.GET("/custom", handler).
WithPathParam("id", "Unique identifier", "123").
WithQueryParam("filter", "Filter criteria", "active")Validate generated input before you call the public builders; the root mux API intentionally omits the internal Err-returning variants.
The framework automatically infers OpenAPI schemas from example values:
// String parameter -> OpenAPI type: "string"
.WithPathParam("name", "Name of the entity", "john")
// Integer parameter -> OpenAPI type: "integer"
.WithQueryParam("age", "Age in years", 25)
// Boolean parameter -> OpenAPI type: "boolean"
.WithQueryParam("active", "Filter by active status", true)
// UUID -> OpenAPI type: "string", format: "uuid"
.WithPathParam("id", "Unique identifier", uuid.UUID{})
// Time -> OpenAPI type: "string", format: "date-time"
.WithQueryParam("createdAt", "Creation timestamp", time.Time{})
// Arrays -> OpenAPI type: "array"
.WithQueryParam("tags", "List of tags", []string{})
// Maps -> OpenAPI type: "object" with additionalProperties
.WithQueryParam("metadata", "Additional metadata", map[string]string{})Supported Types:
- Primitives:
string,int,int64,float64,bool - Standard library:
uuid.UUID,time.Time,net.IP,url.URL - Collections:
[]T(arrays),map[string]T(objects) - Structs: Referenced as
#/components/schemas/TypeName
router.GET("/openapi.json", func(c mux.RouteContext) {
spec, err := mux.GenerateSpecWithGenerator(mux.NewGenerator(), router)
if err != nil {
c.ServerError("Failed to generate OpenAPI spec", err.Error())
return
}
c.OK(spec)
})api := router.Group("/api")
api.WithTags("API v1")router := mux.NewRouter(
mux.WithContextPooling(), // Enable context pooling
mux.WithHeadFallbackToGet(), // AUTO handle HEAD requests
mux.WithMaxBodyBytes(10<<20), // Set max body size (10MB)
)// Custom health check
router.GET("/health", func(c mux.RouteContext) {
c.OK(map[string]string{
"status": "healthy",
"version": "1.0.0",
})
})
// Built-in Kubernetes-style probes (always returns "ok")
router.Healthz() // GET /healthz
router.Livez() // GET /livez
router.Readyz() // GET /readyz
// With custom health checks
router.HealthzWithReady(func(c mux.RouteContext) bool {
return db.Ping() == nil && cache.Ready()
})
router.LivezWithCheck(func(c mux.RouteContext) bool {
// Check if app is alive (not deadlocked)
return runtime.NumGoroutine() < 10000
})
router.ReadyzWithCheck(func(c mux.RouteContext) bool {
// Check if ready to serve traffic
return db.Ready() && cache.Ready() && migration.Complete()
})users := router.Group("/users")
users.GET("/", listUsers) // List all
users.POST("/", createUser) // Create
users.GET("/{id}", getUser) // Get one
users.PUT("/{id}", updateUser) // Update
users.DELETE("/{id}", deleteUser) // Deletefunc createUser(c mux.RouteContext) {
var user User
if err := c.Bind(&user); err != nil {
c.BadRequest("Invalid request", err.Error())
return
}
if err := validate(user); err != nil {
c.BadRequest("Validation failed", err.Error())
return
}
c.Created(user)
}func listUsers(c mux.RouteContext) {
page, ok := c.Query().String("page")
if !ok {
page = "1"
}
limit, ok := c.Query().String("limit")
if !ok {
limit = "10"
}
// Fetch paginated data
users, total := getUsers(page, limit)
c.OK(map[string]any{
"data": users,
"total": total,
"page": page,
})
}router.POST("/upload", func(c mux.RouteContext) {
file, header, err := c.Request().FormFile("file")
if err != nil {
c.BadRequest("Missing file", "no file uploaded")
return
}
defer file.Close()
// Process file...
c.OK(map[string]string{
"filename": header.Filename,
"size": fmt.Sprintf("%d", header.Size),
})
})mux.UseLogging(router) // Logs all requests// The router will log warnings for conflicting routesfunc handler(c mux.RouteContext) {
fmt.Printf("Method: %s\n", c.Request().Method)
fmt.Printf("Path: %s\n", c.Request().URL.Path)
fmt.Printf("Headers: %v\n", c.Request().Header)
}-
Enable Context Pooling for high-traffic APIs
router := mux.NewRouter(mux.WithContextPooling())
-
Use Compression for large responses
mux.UseCompression(router)
-
Set Appropriate Limits
router := mux.NewRouter(mux.WithMaxBodyBytes(5<<20)) // 5MB
-
Cache OpenAPI Spec instead of generating on every request
- One response per request - Don't call
c.OK()multiple times - Always validate input - Use
c.Bind()for type safety - Handle errors gracefully - Use appropriate status codes
- Document your API - Use OpenAPI annotations
- Test your endpoints - Write tests for critical paths
Print this page for quick reference while coding!
- Quick Start - Get running in 5 minutes
- Getting Started - Comprehensive introduction
- Interactive Tutorial - Build a Todo API
- Learning Path - Structured learning progression
- Router - Routing fundamentals
- Middleware - Built-in middleware guide