Routing
This documentation explains how to handle HTTP requests in Confetti Framework using standard Go techniques and the built-in routing system with handler.New(). This provides full control over routes and middleware without external libraries.
Defining Routes
Routes are defined using handler.New("METHOD PATH", handlerFunc). Middleware can be added via .AppendMiddleware().
Example:
var ApiRoutes = []handler.Route{
	handler.New("GET /ping", ping.Index),
	handler.New("GET /status", status.Index).AppendMiddleware(middleware.AuthMiddleware{Permission: "Show status"}),
}
The GET /ping route is added without middleware, while the GET /status route requires authentication with the appropriate permission.
Controller Structure
Controllers must use the following function signature:
func Index(response http.ResponseWriter, request *http.Request) error {
    // Processing logic here
    return nil
}
Parameters:
- response: The 
http.ResponseWriterused to write the response. - request: The 
*http.Requestcontaining the incoming request. - error: Returns an error if a problem occurs.
 
Enhanced Routing Patterns
The Go 1.22+ routing system allows for more expressive patterns:
Method-Specific Routes
Routes can be defined with HTTP methods for stricter matching. For example, POST /items/create ensures only POST requests are allowed for that route.
Wildcard Parameters
{param}captures a single path segment and can be retrieved usingrequest.PathValue("param").{param...}matches multiple segments at the end of a path.
Example:
func ShowFile(response http.ResponseWriter, request *http.Request) error {
    filePath := request.PathValue("path")
    fmt.Fprintf(response, "File path: %s", filePath)
    return nil
}
For the route GET /files/{path...}, path captures all remaining segments.
Exact Matches
To ensure an exact match with a trailing slash, use {$}:
handler.New("GET /users/{$}", user.List)
Working with Route Parameters
Example:
func ShowUser(response http.ResponseWriter, request *http.Request) error {
    userID := request.PathValue("id")
    fmt.Fprintf(response, "User ID: %s", userID)
    return nil
}
For a route like GET /users/{id}, the {id} value is retrieved using request.PathValue("id").
Query Parameters
Query parameters can be extracted directly from the *http.Request:
func Search(response http.ResponseWriter, request *http.Request) error {
    query := request.URL.Query().Get("q")
    fmt.Fprintf(response, "Search results for: %s", query)
    return nil
}
Redirects
To implement a redirect in an idiomatic Go way:
func RedirectToHome(response http.ResponseWriter, request *http.Request) error {
    http.Redirect(response, request, "/home", http.StatusFound)
    return nil
}
Regular Expression Constraints
Regular expressions can be used in routes to validate parameters. Example:
var ApiRoutes = []handler.Route{
    handler.New("GET /product/{id:[0-9]+}", product.Show),
}
Here, {id} is restricted to numeric values ([0-9]+).
Form Data
To process form submissions, first parse the form data:
func ProcessForm(response http.ResponseWriter, request *http.Request) error {
    request.ParseForm()
    name := request.Form.Get("name")
    fmt.Fprintf(response, "Received name: %s", name)
    return nil
}
Raw Request Body
To read the raw request body:
import "io"
func ReadBody(response http.ResponseWriter, request *http.Request) error {
    bodyBytes, err := io.ReadAll(request.Body)
    if err != nil {
        http.Error(response, "Error reading body", http.StatusInternalServerError)
        return err
    }
    bodyString := string(bodyBytes)
    fmt.Fprintf(response, "Request body: %s", bodyString)
    return nil
}
Handling Cookies
Retrieve cookies using:
func GetSessionCookie(response http.ResponseWriter, request *http.Request) error {
    cookie, err := request.Cookie("session_id")
    if err != nil {
        http.Error(response, "Session cookie missing", http.StatusUnauthorized)
        return err
    }
    fmt.Fprintf(response, "Session ID: %s", cookie.Value)
    return nil
}
Handling File Uploads
For file uploads, use request.FormFile():
func UploadFile(response http.ResponseWriter, request *http.Request) error {
    file, header, err := request.FormFile("photo")
    if err != nil {
        http.Error(response, "Error retrieving file", http.StatusBadRequest)
        return err
    }
    defer file.Close()
    fmt.Fprintf(response, "Uploaded file: %s", header.Filename)
    return nil
}