Routing

Organize routes with groups, versioning, and static files.

Route Registration

HTTP Method Shortcuts

Register routes using HTTP method shortcuts:

a.GET("/users", handler)
a.POST("/users", handler)
a.PUT("/users/:id", handler)
a.PATCH("/users/:id", handler)
a.DELETE("/users/:id", handler)
a.HEAD("/users", handler)
a.OPTIONS("/users", handler)

Match All Methods

Register a route that matches all HTTP methods:

a.Any("/webhook", webhookHandler)
// Handles GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS

Route Groups

Basic Groups

Organize routes with shared prefixes:

api := a.Group("/api")
api.GET("/users", getUsersHandler)
api.POST("/users", createUserHandler)
// Routes: GET /api/users, POST /api/users

Nested Groups

Create hierarchical route structures:

api := a.Group("/api")
v1 := api.Group("/v1")
v1.GET("/users", getUsersHandler)
// Route: GET /api/v1/users

Groups with Middleware

Apply middleware to all routes in a group:

admin := a.Group("/admin", AuthMiddleware(), AdminOnlyMiddleware())
admin.GET("/users", getUsersHandler)
admin.POST("/users", createUserHandler)
// Both routes have auth and admin middleware

API Versioning

Version Groups

Create version-specific routes:

v1 := a.Version("v1")
v1.GET("/users", v1GetUsersHandler)

v2 := a.Version("v2")
v2.GET("/users", v2GetUsersHandler)

Version Detection

Configure how versions are detected. This requires router configuration:

a, err := app.New(
    app.WithRouter(
        router.WithVersioning(
            router.WithVersionHeader("API-Version"),
            router.WithVersionQuery("version"),
        ),
    ),
)

Static Files

Serve Directory

Serve static files from a directory:

a.Static("/static", "./public")
// Files in ./public served at /static/*

Serve Single File

Serve a single file at a specific path:

a.File("/favicon.ico", "./static/favicon.ico")
a.File("/robots.txt", "./static/robots.txt")

Serve from Filesystem

Serve files from an http.FileSystem:

//go:embed static
var staticFiles embed.FS

a.StaticFS("/assets", http.FS(staticFiles))

Route Naming

Named Routes

Name routes for URL generation:

a.GET("/users/:id", getUserHandler).Name("users.get")
a.POST("/users", createUserHandler).Name("users.create")

Generate URLs

Generate URLs from route names:

// After router is frozen (after a.Start())
url, err := a.URLFor("users.get", map[string]string{"id": "123"}, nil)
// Returns: "/users/123"

// With query parameters
url, err := a.URLFor("users.get", 
    map[string]string{"id": "123"},
    map[string][]string{"expand": {"profile"}},
)
// Returns: "/users/123?expand=profile"

Must Generate URLs

Generate URLs and panic on error:

url := a.MustURLFor("users.get", map[string]string{"id": "123"}, nil)

Route Constraints

Numeric Constraints

Constrain parameters to numeric values:

a.GET("/users/:id", handler).WhereInt("id")
// Only matches /users/123, not /users/abc

UUID Constraints

Constrain parameters to UUIDs:

a.GET("/orders/:id", handler).WhereUUID("id")
// Only matches valid UUIDs

Custom Constraints

Use regex patterns for custom constraints:

a.GET("/posts/:slug", handler).Where("slug", `[a-z\-]+`)
// Only matches lowercase letters and hyphens

Custom 404 Handler

Set NoRoute Handler

Handle routes that don’t match:

a.NoRoute(func(c *app.Context) {
    c.JSON(http.StatusNotFound, map[string]string{
        "error": "route not found",
        "path": c.Request.URL.Path,
    })
})

Complete Example

package main

import (
    "log"
    "net/http"
    
    "rivaas.dev/app"
)

func main() {
    a := app.MustNew(
        app.WithServiceName("api"),
    )
    
    // Root routes
    a.GET("/", homeHandler)
    a.GET("/health", healthHandler)
    
    // API v1
    v1 := a.Group("/api/v1")
    v1.GET("/status", statusHandler)
    
    // Users
    users := v1.Group("/users")
    users.GET("", getUsersHandler).Name("users.list")
    users.POST("", createUserHandler).Name("users.create")
    users.GET("/:id", getUserHandler).Name("users.get").WhereInt("id")
    users.PUT("/:id", updateUserHandler).Name("users.update").WhereInt("id")
    users.DELETE("/:id", deleteUserHandler).Name("users.delete").WhereInt("id")
    
    // Admin routes with authentication
    admin := a.Group("/admin", AuthMiddleware())
    admin.GET("/dashboard", dashboardHandler)
    admin.GET("/users", adminGetUsersHandler)
    
    // Static files
    a.Static("/assets", "./public")
    a.File("/favicon.ico", "./public/favicon.ico")
    
    // Custom 404
    a.NoRoute(func(c *app.Context) {
        c.NotFound("route not found")
    })
    
    // Start server...
}

Next Steps

  • Middleware - Add middleware to routes and groups
  • Context - Access route parameters and query strings
  • Examples - See complete working examples