Home /
Rig is a lightweight HTTP framework for Go that wraps net/http with zero external dependencies. Built for Go 1.22+, it provides the ergonomics of popular frameworks while staying true to the standard library.
- Zero Dependencies - Only the Go standard library (core package)
- Go 1.22+ Pattern Matching - Full support for method routing and path parameters
- Middleware - Global, group, and per-route middleware with onion-style execution
- Route Groups - Organize routes with shared prefixes and middleware
- JSON Handling -
Bind,BindStrict, andJSONresponse helpers - Static Files - Serve directories with a single line
- Production Middleware - Built-in
Recover,CORS, andTimeoutmiddleware - Production-Safe Timeouts - Server and request timeouts with Slowloris protection
- Graceful Shutdown - Zero-downtime deployments with
RunGracefully() - Health Checks - Liveness and readiness probes with timeout support for Kubernetes
- HTML Templates - Template rendering with layouts, partials, embed.FS, and content negotiation (
render/sub-package) - Authentication - API Key and Bearer Token middleware (
auth/sub-package) - Request ID - ULID-based request tracking (
requestid/sub-package) - Logging - Structured request logging with JSON support (
logger/sub-package) - Swagger UI - Optional sub-package for API documentation
- Type-Safe Context - Generic
GetType[T]for dependency injection - 99%+ Test Coverage - Battle-tested and production-ready
go get github.com/cloudresty/rigRequires Go 1.22 or later.
package main
import (
"net/http"
"github.com/cloudresty/rig"
)
func main() {
r := rig.New()
// Add middleware
r.Use(rig.Recover())
r.Use(rig.DefaultCORS())
// Simple route
r.GET("/", func(c *rig.Context) error {
return c.JSON(http.StatusOK, map[string]string{
"message": "Hello, World!",
})
})
// Path parameters (Go 1.22+)
r.GET("/users/{id}", func(c *rig.Context) error {
id := c.Param("id")
return c.JSON(http.StatusOK, map[string]string{
"user_id": id,
})
})
http.ListenAndServe(":8080", r)
}
Organize routes with shared prefixes and middleware:
r := rig.New()
// API group with authentication middleware
api := r.Group("/api")
api.Use(authMiddleware)
api.GET("/users", listUsers) // GET /api/users
api.POST("/users", createUser) // POST /api/users
api.GET("/users/{id}", getUser) // GET /api/users/{id}
// Nested groups
v1 := api.Group("/v1")
v1.GET("/status", getStatus) // GET /api/v1/status
Middleware follows the decorator pattern with onion-style execution:
// Custom middleware
func Logger() rig.MiddlewareFunc {
return func(next rig.HandlerFunc) rig.HandlerFunc {
return func(c *rig.Context) error {
start := time.Now()
err := next(c)
log.Printf("%s %s %v", c.Method(), c.Path(), time.Since(start))
return err
}
}
}
// Apply middleware
r.Use(rig.Recover()) // Global - catches panics
r.Use(rig.DefaultCORS()) // Global - enables CORS
r.Use(Logger()) // Global - logs requests
| Middleware | Description |
|---|---|
Recover() |
Catches panics and returns a 500 JSON error |
DefaultCORS() |
Permissive CORS (allows all origins) |
CORS(config) |
Configurable CORS with specific origins/methods/headers |
Timeout(duration) |
Cancels request context after specified duration |
Additional middleware sub-packages (see sections below):
| Package | Description |
|---|---|
auth/ |
API Key and Bearer Token authentication |
requestid/ |
ULID-based request ID generation |
logger/ |
Structured request logging (text/JSON) |
r.GET("/users/{id}", func(c *rig.Context) error {
id := c.Param("id")
// ...
})
r.GET("/search", func(c *rig.Context) error {
q := c.Query("q") // Single value
tags := c.QueryArray("tag") // Multiple values: ?tag=a&tag=b
page := c.QueryDefault("page", "1") // With default
// ...
})
r.POST("/users", func(c *rig.Context) error {
var user User
if err := c.Bind(&user); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
}
// Use c.BindStrict(&user) to reject unknown fields
// ...
})
r.POST("/login", func(c *rig.Context) error {
username := c.FormValue("username") // Body takes precedence over query
password := c.PostFormValue("password") // Body only
// ...
})
// JSON response
c.JSON(http.StatusOK, data)
// String response
c.WriteString("Hello")
// Redirect
c.Redirect(http.StatusFound, "/new-location")
// Serve a file
c.File("./reports/monthly.pdf")
// Raw bytes
c.Data(http.StatusOK, "image/png", pngBytes)
// Set status only
c.Status(http.StatusNoContent)
Serve a directory of static files:
r.Static("/assets", "./public")
// GET /assets/css/style.css → serves ./public/css/style.css
For production, enable cache headers to improve performance:
// Cache for 1 year (recommended for versioned assets like app.v1.2.3.js)
r.Static("/assets", "./public", rig.StaticConfig{
CacheControl: "public, max-age=31536000",
})
// Cache for 1 day (for assets that may change)
r.Static("/images", "./images", rig.StaticConfig{
CacheControl: "public, max-age=86400",
})
// No caching (for development or dynamic assets)
r.Static("/uploads", "./uploads", rig.StaticConfig{
CacheControl: "no-cache",
})
| Cache-Control Value | Use Case |
|---|---|
public, max-age=31536000 |
Versioned assets (CSS, JS with hash in filename) |
public, max-age=86400 |
Assets that may change daily |
public, max-age=3600 |
Assets that may change hourly |
no-cache |
Always revalidate with server |
no-store |
Never cache (sensitive data) |
Use the context store for request-scoped values:
// Middleware: inject dependencies
func InjectDB(db *Database) rig.MiddlewareFunc {
return func(next rig.HandlerFunc) rig.HandlerFunc {
return func(c *rig.Context) error {
c.Set("db", db)
return next(c)
}
}
}
// Handler: retrieve with type safety
r.GET("/users", func(c *rig.Context) error {
db, err := rig.GetType[*Database](c, "db")
if err != nil {
return err
}
// Use db...
})
// Permissive (all origins)
r.Use(rig.DefaultCORS())
// Restrictive with exact origins
r.Use(rig.CORS(rig.CORSConfig{
AllowOrigins: []string{"https://myapp.com", "https://admin.myapp.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowHeaders: []string{"Content-Type", "Authorization"},
}))
// Wildcard subdomain support
r.Use(rig.CORS(rig.CORSConfig{
AllowOrigins: []string{
"https://*.myapp.com", // Matches any subdomain
"https://*.staging.myapp.com", // Matches nested subdomains
"https://api.production.com", // Exact match also works
},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowHeaders: []string{"Content-Type", "Authorization"},
}))
AllowOrigins patterns:
| Pattern | Matches | Does Not Match |
|---|---|---|
"*" |
All origins | - |
"https://example.com" |
Exact match only | https://sub.example.com |
"https://*.example.com" |
https://app.example.com, https://a.b.example.com |
https://example.com, http://app.example.com |
Rig provides an opt-in health utility for liveness and readiness probes, perfect for Kubernetes deployments:
func main() {
r := rig.New()
db := connectDB()
// Create the Health manager
health := rig.NewHealth()
// Add readiness check (don't send traffic if DB is down)
health.AddReadinessCheck("database", func() error {
return db.Ping()
})
// Add liveness check (is the app running?)
health.AddLivenessCheck("ping", func() error {
return nil // Always healthy
})
// Mount the handlers (user chooses the paths)
h := r.Group("/health")
h.GET("/live", health.LiveHandler())
h.GET("/ready", health.ReadyHandler())
r.Run(":8080")
}
Response format:
// GET /health/ready (all checks pass)
{ "status": "OK", "checks": { "database": "OK" } }
// GET /health/ready (a check fails)
{ "status": "Service Unavailable", "checks": { "database": "FAIL: connection refused" } }
| Method | Description |
|---|---|
NewHealth() |
Creates a new Health manager with default 5s timeout |
NewHealthWithConfig(config) |
Creates a Health manager with custom configuration |
AddReadinessCheck(name, fn) |
Adds a check for traffic readiness (DB, Redis, etc.) |
AddReadinessCheckContext(name, fn) |
Adds a context-aware check that respects timeouts |
AddLivenessCheck(name, fn) |
Adds a check for app liveness (deadlock detection, etc.) |
LiveHandler() |
Returns a handler for liveness probes |
ReadyHandler() |
Returns a handler for readiness probes |
Health checks have built-in timeout protection to prevent slow checks from blocking health endpoints:
// Custom timeout configuration
config := rig.HealthConfig{
CheckTimeout: 10 * time.Second, // Per-check timeout (default: 5s)
Parallel: true, // Run checks concurrently (default: false)
}
health := rig.NewHealthWithConfig(config)
// Context-aware check (receives timeout via context)
health.AddReadinessCheckContext("database", func(ctx context.Context) error {
return db.PingContext(ctx) // Respects the timeout
})
// Per-check timeout override
health.AddReadinessCheckWithTimeout("slow-service", 30*time.Second, func(ctx context.Context) error {
return slowService.HealthCheck(ctx)
})
Rig provides production-safe timeout defaults to protect against Slowloris attacks and cascading failures.
The Run() method applies production-safe defaults automatically:
r := rig.New()
r.Run(":8080") // Uses DefaultServerConfig()
| Default | Value | Purpose |
|---|---|---|
ReadHeaderTimeout |
5s | Critical Slowloris protection (headers only) |
WriteTimeout |
10s | Prevents slow response consumption |
IdleTimeout |
120s | Allows keep-alive but not indefinitely |
ReadTimeout |
0 | No body limit (allows slow uploads) |
MaxHeaderBytes |
1MB | Prevents header size attacks |
Custom Configuration:
config := rig.DefaultServerConfig()
config.Addr = ":8080"
config.WriteTimeout = 30 * time.Second // Allow longer responses
r.RunWithConfig(config)
Use Timeout() middleware to cancel slow handlers and prevent cascading failures:
r := rig.New()
r.Use(rig.Timeout(5 * time.Second))
r.GET("/api/data", func(c *rig.Context) error {
// This query will be cancelled if it takes > 5s
result, err := db.QueryContext(c.Context(), "SELECT ...")
if err != nil {
return err // Returns context.DeadlineExceeded if timed out
}
return c.JSON(http.StatusOK, result)
})
Custom timeout response:
r.Use(rig.TimeoutWithConfig(rig.TimeoutConfig{
Timeout: 5 * time.Second,
OnTimeout: func(c *rig.Context) error {
return c.JSON(http.StatusGatewayTimeout, map[string]string{
"error": "Request timed out",
})
},
}))
IMPORTANT
Handlers must checkc.Context()for this to work effectively. Usedb.QueryContext(c.Context(), ...)instead ofdb.Query(...).
Rig provides zero-downtime deployment support with RunGracefully(). When the server receives a shutdown signal (SIGINT or SIGTERM), it:
- Stops accepting new connections
- Waits for in-flight requests to complete
- Exits cleanly after the timeout
This prevents dropped connections and 502 errors during deployments.
func main() {
r := rig.New()
r.GET("/", func(c *rig.Context) error {
time.Sleep(2 * time.Second) // Simulate work
return c.JSON(http.StatusOK, map[string]string{"status": "done"})
})
// Ctrl+C will wait for the 2s request to finish before exiting
if err := r.RunGracefully(":8080"); err != nil {
log.Fatal(err)
}
}
| Method | Description |
|---|---|
Run(addr) |
Simple start for development/testing |
RunGracefully(addr) |
Production-ready with graceful shutdown (recommended) |
RunWithGracefulShutdown(config) |
Graceful shutdown with custom configuration |
RunWithConfig(config) |
Custom config without graceful shutdown |
Custom shutdown timeout:
config := rig.DefaultServerConfig()
config.Addr = ":8080"
config.ShutdownTimeout = 30 * time.Second // Wait longer for in-flight requests
if err := r.RunWithGracefulShutdown(config); err != nil {
log.Fatal(err)
}
Rig provides optional Swagger UI support via a separate sub-package to keep the core framework dependency-free:
go get github.com/cloudresty/rig/swagger
package main
import (
"github.com/cloudresty/rig"
"github.com/cloudresty/rig/swagger"
_ "myapp/docs" // Generated by: swag init
)
func main() {
r := rig.New()
// Your API routes
r.GET("/api/v1/users", handleUsers)
// Register Swagger UI at /docs/
sw := swagger.NewFromSwag("swagger")
sw.Register(r, "/docs")
r.Run(":8080")
}
// Access Swagger UI at http://localhost:8080/docs/
spec := `{"openapi":"3.0.0","info":{"title":"My API","version":"1.0"}}`
sw := swagger.New(spec).
WithTitle("My API Documentation").
WithDocExpansion("list")
sw.Register(r, "/api-docs")
api := r.Group("/api/v1")
sw := swagger.NewFromSwag("swagger")
sw.RegisterGroup(api, "/docs")
// Access at /api/v1/docs/
| Method | Description |
|---|---|
New(specJSON) |
Creates Swagger UI with a JSON spec string |
NewFromSwag(name) |
Creates Swagger UI from swaggo/swag registered spec |
WithTitle(title) |
Sets the page title |
WithDeepLinking(bool) |
Enables/disables URL deep linking (default: true) |
WithDocExpansion(mode) |
Sets expansion mode: "list", "full", "none" |
Register(router, path) |
Registers routes on a Router |
RegisterGroup(group, path) |
Registers routes on a RouteGroup |
The auth/ sub-package provides API Key and Bearer Token authentication:
go get github.com/cloudresty/rig/auth
import "github.com/cloudresty/rig/auth"
// Simple: validate against a list of keys
api := r.Group("/api")
api.Use(auth.APIKeySimple("key1", "key2", "key3"))
// Advanced: custom validation with identity
api.Use(auth.APIKey(auth.APIKeyConfig{
Name: "X-API-Key", // Header name (default)
Source: "header", // "header" or "query"
Validator: func(key string) (identity string, valid bool) {
if key == os.Getenv("API_KEY") {
return "my-service", true
}
return "", false
},
}))
// In handlers, get the authenticated identity
r.GET("/profile", func(c *rig.Context) error {
identity := auth.GetIdentity(c) // Returns identity from Validator
method := auth.GetMethod(c) // Returns "api_key" or "bearer"
return c.JSON(http.StatusOK, map[string]string{"user": identity})
})
api.Use(auth.Bearer(auth.BearerConfig{
Realm: "API",
Validator: func(token string) (identity string, valid bool) {
// Validate JWT or lookup token
claims, err := validateJWT(token)
if err != nil {
return "", false
}
return claims.UserID, true
},
}))
| Function | Description |
|---|---|
APIKeySimple(keys...) |
Simple API key validation (constant-time comparison) |
APIKey(config) |
Configurable API key middleware |
Bearer(config) |
Bearer token middleware (RFC 6750) |
GetIdentity(c) |
Get authenticated identity from context |
GetMethod(c) |
Get auth method ("api_key" or "bearer") |
IsAuthenticated(c) |
Check if request is authenticated |
The requestid/ sub-package generates unique request IDs using ULIDs:
go get github.com/cloudresty/rig/requestid
import "github.com/cloudresty/rig/requestid"
r := rig.New()
// Add request ID middleware (generates ULID for each request)
r.Use(requestid.New())
// With custom configuration
r.Use(requestid.New(requestid.Config{
Header: "X-Request-ID", // Response header (default)
TrustProxy: true, // Trust incoming X-Request-ID header
Generator: func() (string, error) {
return uuid.New().String(), nil // Use UUID instead of ULID
},
}))
// In handlers, get the request ID
r.GET("/", func(c *rig.Context) error {
reqID := requestid.Get(c)
return c.JSON(http.StatusOK, map[string]string{
"request_id": reqID,
})
})
| Function | Description |
|---|---|
New() |
Create middleware with default config |
New(config) |
Create middleware with custom config |
Get(c) |
Get request ID from context |
The logger/ sub-package provides structured request logging:
go get github.com/cloudresty/rig/logger
import "github.com/cloudresty/rig/logger"
r := rig.New()
// Add request ID first (logger will include it)
r.Use(requestid.New())
// Add logger middleware
r.Use(logger.New(logger.Config{
Format: logger.FormatJSON, // FormatText or FormatJSON
Output: os.Stdout, // io.Writer
SkipPaths: []string{"/health", "/ready"}, // Don't log these paths
}))
Text format output:
2024/01/15 10:30:45 | 200 | 1.234ms | 192.168.1.1 | GET /api/users | req_id: 01HQ...
JSON format output:
{"time":"2024-01-15T10:30:45Z","status":200,"latency":"1.234ms","latency_ms":1.234,"client_ip":"192.168.1.1","method":"GET","path":"/api/users","request_id":"01HQ..."}
| Option | Description |
|---|---|
Format |
FormatText (default) or FormatJSON |
Output |
io.Writer for log output (default: os.Stdout) |
SkipPaths |
Paths to exclude from logging (e.g., health checks) |
The render sub-package provides HTML template rendering with layouts, partials, hot reloading, and content negotiation.
go get github.com/cloudresty/rig/render
import (
"github.com/cloudresty/rig"
"github.com/cloudresty/rig/render"
)
func main() {
engine := render.New(render.Config{
Directory: "./templates",
})
r := rig.New()
r.Use(engine.Middleware())
r.GET("/", func(c *rig.Context) error {
return render.HTML(c, http.StatusOK, "home", map[string]any{
"Title": "Welcome",
"User": "John",
})
})
r.Run(":8080")
}
For single-binary deployments, embed templates directly into your Go binary:
import (
"embed"
"github.com/cloudresty/rig/render"
)
//go:embed templates/*
var templateFS embed.FS
func main() {
engine := render.New(render.Config{
FileSystem: templateFS,
Directory: "templates",
})
// Templates are now compiled into the binary!
}
engine := render.New(render.Config{
Directory: "./templates",
Layout: "layouts/base", // Base layout template
})
Layout template (templates/layouts/base.html):
<!DOCTYPE html>
<html>
<head><title>{{.Data.Title}}</title></head>
<body>
<header>My Site</header>
<main>{{.Content}}</main>
<footer>© 2026</footer>
</body>
</html>
Page template (templates/home.html):
<h1>Welcome, {{.User}}!</h1>
Layout Data Access:
In layouts, data is available via {{.Data}} (works with both structs and maps):
| Expression | Description |
|---|---|
{{.Content}} |
Rendered page content |
{{.Data.Title}} |
Access data fields (works with structs!) |
{{.Title}} |
Direct access (backward compatible with maps) |
Templates starting with underscore (_) are automatically treated as partials and available to all templates:
templates/
├── _sidebar.html ← Partial (available everywhere)
├── _footer.html ← Partial (available everywhere)
├── home.html
└── about.html
Use partials in any template:
<div class="page">
{{template "_sidebar" .}}
<main>{{.Content}}</main>
{{template "_footer" .}}
</div>
For larger applications, use SharedDirs to designate entire directories as globally available partials. This enables component-based architecture without requiring underscore prefixes:
engine := render.New(render.Config{
Directory: "./templates",
Layout: "layouts/base",
SharedDirs: []string{"components", "layouts", "base"},
})
Example directory structure:
templates/
├── components/ ← Shared (available everywhere)
│ ├── button.html
│ ├── card.html
│ └── forms/
│ └── input.html
├── base/ ← Shared (available everywhere)
│ └── modal.html
├── layouts/ ← Shared (available everywhere)
│ └── base.html
└── features/ ← Feature templates (isolated)
├── dashboard/
│ └── index.html
└── users/
├── list.html
└── profile.html
Feature templates can include shared components:
<!-- features/dashboard/index.html -->
<h1>Dashboard</h1>
{{template "components/button" "Click Me"}}
{{template "components/card" .Stats}}
{{template "base/modal" .ModalData}}
This approach keeps feature pages isolated while sharing common components across the application. The underscore convention still works alongside SharedDirs - files starting with _ are always treated as partials regardless of their directory.
For HTMX requests, AJAX updates, or any scenario where you need to render a fragment without the layout wrapper, use Partial():
// HTMX endpoint - returns just the table rows, no layout
r.GET("/users/table", func(c *rig.Context) error {
users := getUsers()
return render.Partial(c, http.StatusOK, "components/user-table", map[string]any{
"Users": users,
})
})
// Dynamic widget update
r.GET("/dashboard/stats", func(c *rig.Context) error {
stats := getStats()
return render.Partial(c, http.StatusOK, "_stats-widget", stats)
})
| Function | Description |
|---|---|
render.Partial(c, status, name, data) |
Render partial via middleware (recommended) |
render.PartialDirect(c, engine, status, name, data) |
Render partial with explicit engine |
engine.RenderPartial(name, data) |
Low-level: returns HTML string |
Key differences from HTML():
- Looks up templates in the shared partials set only (not regular templates)
- Never wraps output in a layout
- Perfect for HTMX
hx-get/hx-postresponses
Render JSON or XML directly without templates:
// JSON response
r.GET("/api/users", func(c *rig.Context) error {
return render.JSON(c, http.StatusOK, users)
})
// XML response
r.GET("/api/users.xml", func(c *rig.Context) error {
return render.XML(c, http.StatusOK, users)
})
Use Auto() to automatically select the response format based on the Accept header:
r.GET("/users", func(c *rig.Context) error {
// Returns HTML for browsers, JSON for API clients
return render.Auto(c, http.StatusOK, "users/list", users)
})
| Accept Header | Response Format |
|---|---|
application/json |
JSON |
application/xml or text/xml |
XML |
text/html or other |
HTML (if template provided) |
| No template provided | JSON (fallback) |
Use HTMLSafe() to automatically render a pretty error page when template rendering fails:
r.GET("/page", func(c *rig.Context) error {
return render.HTMLSafe(c, http.StatusOK, "page", data, "errors/500")
})
If "page" fails to render, it automatically falls back to "errors/500" with error details:
<!-- templates/errors/500.html -->
<h1>Something went wrong</h1>
<p>Error: {{.Error}}</p>
<p>Status: {{.StatusCode}}</p>
Enable hot reloading during development:
engine := render.New(render.Config{
Directory: "./templates",
DevMode: true, // Reloads templates on each request
})
Enable HTML minification for production to reduce bandwidth and improve page load times:
engine := render.New(render.Config{
Directory: "./templates",
Minify: true, // Minify HTML output
})
The minifier is enterprise-grade and safe:
| Feature | Description |
|---|---|
| Block element optimization | Removes whitespace between block elements (<div>, <p>, <section>, etc.) |
| Inline element preservation | Preserves spaces between inline elements (<span>A</span> <span>B</span> stays intact) |
| Protected blocks | Preserves whitespace in <pre>, <script>, <style>, and <textarea> |
| Comment removal | Removes HTML comments while preserving IE conditional comments |
| JavaScript safety | Preserves // comments and formatting inside <script> tags |
engine := render.New(render.Config{
Directory: "./templates",
Funcs: template.FuncMap{
"upper": strings.ToUpper,
"formatDate": func(t time.Time) string {
return t.Format("Jan 2, 2006")
},
},
})
// Or use chained methods:
engine.AddFunc("lower", strings.ToLower)
Use in templates: {{upper .Name}} or {{formatDate .CreatedAt}}
| Function | Description | Usage |
|---|---|---|
safe |
Render trusted HTML without escaping | {{safe .RawHTML}} |
safeAttr |
Render trusted HTML attribute | {{safeAttr .Attr}} |
safeURL |
Render trusted URL | {{safeURL .Link}} |
dump |
Debug helper - outputs data as formatted JSON | {{dump .}} |
The dump function is invaluable during development:
<!-- Debug: see what data was passed to the template -->
{{dump .Data}}Outputs:
<pre>{
"Title": "My Page",
"User": {
"Name": "John"
}
}</pre>
For 100+ additional template functions (string manipulation, math, dates, etc.), integrate Sprig:
import "github.com/Masterminds/sprig/v3"
engine := render.New(render.Config{
Directory: "./templates",
})
engine.AddFuncs(sprig.FuncMap())
Now you can use functions like {{.Name | upper}}, {{now | date "2006-01-02"}}, and many more.
When using frontend frameworks that also use {{ }} syntax, configure custom delimiters:
engine := render.New(render.Config{
Directory: "./templates",
Delims: []string{"[[", "]]"}, // Use [[ ]] for Go templates
})
Now your templates can mix Go and Vue/Angular syntax:
<div>
<!-- Go template (rendered on server) -->
<h1>[[ .Title ]]</h1>
<!-- Vue.js binding (rendered on client) -->
<p>{{ message }}</p>
</div>
List loaded templates and partials:
engine.TemplateNames() // Returns all template names
engine.PartialNames() // Returns all partial names (files starting with _)
The examples/ directory contains runnable examples:
| Example | Description |
|---|---|
| basic-api | REST API with middleware, dependency injection, and route groups |
| health-checks | Kubernetes-style liveness and readiness probes |
| swagger-ui | API with integrated Swagger UI documentation |
| auth-middleware | API Key authentication using the auth/ package |
| logging | Request logging with request ID tracking |
| render-templates | HTML templates with layouts, partials, and content negotiation |
| Method | Description |
|---|---|
Param(name) |
Get path parameter |
Query(key) |
Get query parameter |
QueryDefault(key, def) |
Get query parameter with default |
QueryArray(key) |
Get all values for a query parameter |
FormValue(key) |
Get form value (body precedence) |
PostFormValue(key) |
Get form value (body only) |
GetHeader(key) |
Get request header |
SetHeader(key, value) |
Set response header |
Bind(v) |
Decode JSON body |
BindStrict(v) |
Decode JSON body (reject unknown fields) |
JSON(code, v) |
Send JSON response |
Status(code) |
Set status code |
Redirect(code, url) |
Send redirect |
File(path) |
Serve a file |
Data(code, contentType, data) |
Send raw bytes |
Set(key, value) |
Store request-scoped value |
Get(key) |
Retrieve stored value |
MustGet(key) |
Retrieve stored value (panics if missing) |
Context() |
Get context.Context |
SetContext(ctx) |
Set context.Context |
Request() |
Get *http.Request |
Writer() |
Get http.ResponseWriter |
| Method | Description |
|---|---|
New() |
Create a new router |
Use(middleware...) |
Add global middleware |
Handle(pattern, handler) |
Register a handler |
GET/POST/PUT/DELETE/PATCH/OPTIONS/HEAD(path, handler) |
Register method-specific handler |
Group(prefix) |
Create a route group |
Static(path, root) |
Serve static files |
ServeHTTP(w, r) |
Implement http.Handler |
This project is licensed under the MIT License - see the LICENSE file for details.
Website | LinkedIn | BlueSky | GitHub | Docker Hub
© Cloudresty - All rights reserved