TypeFunction

HandlerFunc

Function signature for request handlers that process HTTP requests and generate responses.

Type Definition

type HandlerFunc func(req *Request, res *Response)

Usage Examples

Basic Handler

Simple handler that responds with plain text.

// Define a handler function
func helloHandler(req *Request, res *Response) {
    res.Write("Hello, World!")
    res.Send()
}

func main() {
    server := SpawnServer()
    
    // Use the handler function
    server.Get("/hello", helloHandler)
    
    // Or use an anonymous function
    server.Get("/", func(req *Request, res *Response) {
        res.Write("Welcome to Squirrel!")
        res.Send()
    })
    
    server.Listen(":8080")
}

JSON API Handler

Handler that processes JSON data and returns JSON responses.

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

func createUserHandler(req *Request, res *Response) {
    // Read request body
    body, err := req.ReadBodyAsString()
    if err != nil {
        res.SetStatus(400)
        res.JSON(map[string]string{"error": "Invalid request body"})
        res.Send()
        return
    }
    
    // Parse JSON (simplified - you'd use json.Unmarshal in real code)
    if body == "" {
        res.SetStatus(400)
        res.JSON(map[string]string{"error": "Empty request body"})
        res.Send()
        return
    }
    
    // Create user (simulated)
    user := User{
        ID:    123,
        Name:  "John Doe",
        Email: "john@example.com",
    }
    
    res.SetStatus(201)
    res.JSON(user)
    res.Send()
}

func main() {
    server := SpawnServer()
    server.Post("/api/users", createUserHandler)
    server.Listen(":8080")
}

Handler with URL Parameters

Handler that extracts and uses URL parameters.

func getUserHandler(req *Request, res *Response) {
    userID := req.Param("id")
    
    if userID == "" {
        res.SetStatus(400)
        res.JSON(map[string]string{"error": "User ID is required"})
        res.Send()
        return
    }
    
    // Simulate user lookup
    if userID == "404" {
        res.SetStatus(404)
        res.JSON(map[string]string{"error": "User not found"})
        res.Send()
        return
    }
    
    user := User{
        ID:    123,
        Name:  "John Doe",
        Email: "john@example.com",
    }
    
    res.JSON(user)
    res.Send()
}

func main() {
    server := SpawnServer()
    
    // Route with parameter
    server.Get("/api/users/:id", getUserHandler)
    
    // Multiple parameters
    server.Get("/api/users/:userId/posts/:postId", func(req *Request, res *Response) {
        userID := req.Param("userId")
        postID := req.Param("postId")
        
        res.JSON(map[string]string{
            "userId": userID,
            "postId": postID,
            "message": fmt.Sprintf("Post %s by user %s", postID, userID),
        })
        res.Send()
    })
    
    server.Listen(":8080")
}

Handler with Query Parameters

Handler that processes query string parameters.

func searchHandler(req *Request, res *Response) {
    // Get all query parameters
    queries := req.Query()
    
    // Get specific query parameters
    searchTerms := req.Queries["q"]        // []string
    categories := req.Queries["category"]  // []string
    limitStr := req.Queries["limit"]       // []string
    
    // Process search terms
    if len(searchTerms) == 0 {
        res.SetStatus(400)
        res.JSON(map[string]string{"error": "Search query 'q' is required"})
        res.Send()
        return
    }
    
    // Parse limit (default to 10)
    limit := 10
    if len(limitStr) > 0 {
        if parsedLimit, err := strconv.Atoi(limitStr[0]); err == nil {
            limit = parsedLimit
        }
    }
    
    // Build response
    response := map[string]interface{}{
        "searchTerms": searchTerms,
        "categories":  categories,
        "limit":       limit,
        "results":     []string{"result1", "result2", "result3"},
    }
    
    res.JSON(response)
    res.Send()
}

// Usage: GET /search?q=golang&q=web&category=framework&limit=5

Error Handling Pattern

Best practices for error handling in handlers.

func robustHandler(req *Request, res *Response) {
    // Defer recovery for unexpected panics
    defer func() {
        if r := recover(); r != nil {
            res.SetStatus(500)
            res.JSON(map[string]string{
                "error": "Internal server error",
                "message": "An unexpected error occurred",
            })
            res.Send()
        }
    }()
    
    // Validate request method (if needed)
    if req.Method != "POST" {
        res.SetStatus(405) // Method Not Allowed
        res.SetHeader("Allow", "POST")
        res.JSON(map[string]string{"error": "Method not allowed"})
        res.Send()
        return
    }
    
    // Check content length
    if req.ContentLength > 1024*1024 { // 1MB limit
        res.SetStatus(413) // Payload Too Large
        res.JSON(map[string]string{"error": "Request body too large"})
        res.Send()
        return
    }
    
    // Process request
    body, err := req.ReadBodyAsString()
    if err != nil {
        res.SetStatus(400)
        res.JSON(map[string]string{
            "error": "Failed to read request body",
            "details": err.Error(),
        })
        res.Send()
        return
    }
    
    // Success response
    res.SetStatus(200)
    res.JSON(map[string]string{
        "message": "Request processed successfully",
        "data": body,
    })
    res.Send()
}