Guide / 10 β€” Go Logic

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.