Middleware
Middlewares intercept requests before they reach the page handler. They handle tasks like authentication, logging, CORS, and more.
Creating a Route Middleware
Create a file named stew.middleware.go in the relevant route directory. This file must contain a Middleware function with the standard Go middleware signature:
// pages/admin/stew.middleware.go
package admin
import (
"log"
"net/http"
"time"
)
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Authentication check
token := r.Cookie("session")
if token == nil {
http.Redirect(w, r, "/login", http.StatusFound)
return
}
// Log the request
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("[%s] %s β %v", r.Method, r.URL.Path, time.Since(start))
})
}
Global/Logging Middleware
To apply a middleware to all routes, create it at the root of the pages directory (pages/stew.middleware.go):
// pages/stew.middleware.go
package pages
import (
"log"
"net/http"
)
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("β‘οΈ [REQUEST] %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
log.Printf("β
[SERVED] %s %s", r.Method, r.URL.Path)
})
}
Middleware Chaining
Middlewares are automatically chained based on the directory hierarchy. A parent middleware wraps its child middlewares:
// Example: GET /admin/dashboard
// β pages/stew.middleware.go (Global logging)
// β pages/admin/stew.middleware.go (Auth check)
// β pages/admin/dashboard/@page.stew (Rendering)
// In stew_router_gen.go:
mux.Handle("GET /admin/dashboard",
stew_pages_root.Middleware( // Global wrapper
stew_pages_admin.Middleware( // Admin wrapper
http.HandlerFunc(handler)
)
)
)
Custom HTTP Handlers (stew.server.go)
For non-GET methods (POST, PUT, DELETE, etc.), create a stew.server.go file in the route directory:
// pages/users/stew.server.go
package users
import (
"encoding/json"
"net/http"
)
// POST /users
func Post(w http.ResponseWriter, r *http.Request) {
var body struct{ Name string }
json.NewDecoder(r.Body).Decode(&body)
// ... insert into database ...
w.WriteHeader(http.StatusCreated)
}
// DELETE /users
func Delete(w http.ResponseWriter, r *http.Request) {
// ...
}
The stew generate scanner automatically detects exported functions in stew.server.go and registers them in the router with the HTTP method corresponding to the function name.