Skip to content

FAQ

Frizzante intentionally uses guards instead of middleware.

Middleware have some limitations.

  • All middleware must be invoked for each request
  • Some middleware may contain path-checking logic while others may not, which introduces ambiguity and more details to remember as a developer
  • Managing middleware execution order across different routes is complex

While guards have some advantages.

  • Explicit - you can see exactly which routes use which guards by looking at their tags
  • Efficient - guards only execute when their tags match - no wasted computation
  • Composable - easy to manage execution order per route

For more details see the guard page.

If you really want middleware-like behavior, you can easily implement it in your own project.

lib/middleware/types.go
package middleware
import "main/lib/core/client"
type Hook func(c *client.Client, next func()) // Defines a hook function type which will be used by the middleware.
type Middleware struct { // Defines a structure holds multiple hooks.
Hooks []Hook // Defines the actual hooks slice.
}
lib/middleware/apply.go
package middleware
import (
"main/lib/core/client"
"main/lib/core/route"
)
func Apply(mid *Middleware, routes []route.Route) {
for _, _route := range routes { // For each route...
handler := _route.Handler // ...saves the route handler for later use.
_route.Handler = func(c *client.Client) { // Assigns a new wrapper route handler.
var quit = true // Creates flag used to interrupt the chain.
for _, hook := range mid.Hooks { // For each hook...
quit = true // ...prepares to quit...
hook(c, func() { quit = false }) // ...invokes the hook...
if quit { // Checks if route should quit.
return // Quits.
}
}
handler(c) // Invokes the actual route handler.
}
}
}
main.go
package main
import (
"embed"
"main/lib/core/client"
"main/lib/core/route"
"main/lib/core/server"
"main/lib/core/svelte/ssr"
"main/lib/middleware"
"main/lib/routes/handlers/fallback"
"main/lib/routes/handlers/todos"
"main/lib/routes/handlers/welcome"
"os"
)
//go:embed app/dist
var efs embed.FS
var srv = server.New()
var dev = os.Getenv("DEV") == "1"
var render = ssr.New(ssr.Config{Efs: efs, Disk: dev})
var mid = &middleware.Middleware{ // Creates middleware.
Hooks: []middleware.Hook{ // Creates hooks.
func(c *client.Client, next func()) { // Adds hook.
// Logic goes here.
},
},
}
func main() {
defer server.Start(srv)
defer middleware.Apply(mid, srv.Routes) // Applies middleware to server routes.
// Remember that deferred functions are executed in reverse,
// so this line will execute before the server starts.
srv.Efs = efs
srv.Render = render
srv.Routes = []route.Route{
{Pattern: "GET /", Handler: fallback.View},
{Pattern: "GET /welcome", Handler: welcome.View},
{Pattern: "GET /todos", Handler: todos.View},
{Pattern: "GET /check", Handler: todos.Check},
{Pattern: "GET /uncheck", Handler: todos.Uncheck},
{Pattern: "GET /add", Handler: todos.Add},
{Pattern: "GET /remove", Handler: todos.Remove},
}
}