You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang通用查询REST API实现求助:现有代码仅终端输出需优化

Building a Reusable Generic Query REST API in Go

Hey there! Let's tackle this—first off, the reason you're finding so few results for "Generic REST API Golang" is that the Go community tends to frame this problem around composition and interfaces (or generics, post-Go 1.18) rather than using that exact terminology. You're already on the right track with your existing code; let's shift that terminal output to proper HTTP responses and lock in the "write once, reuse everywhere" goal.

Step 1: Define a Generic Query Interface

Start by creating an interface that all your query handlers will implement. This lets you abstract the core query logic away from HTTP handling:

// QueryHandler defines the contract for any reusable query
type QueryHandler interface {
    Execute(filter map[string]interface{}) (interface{}, error)
}

// Example implementation for a User model
type UserQuery struct{}

func (uq *UserQuery) Execute(filter map[string]interface{}) (interface{}, error) {
    // Replace this with your actual data fetch logic (DB call, etc.)
    // For demo purposes, return mock users
    users := []struct {
        ID   int    `json:"id"`
        Name string `json:"name"`
    }{
        {ID: 1, Name: "Alice"},
        {ID: 2, Name: "Bob"},
    }
    return users, nil
}

Step 2: Build a Reusable HTTP Handler

Now create a generic HTTP handler that takes any QueryHandler, processes the request, runs the query, and returns JSON instead of printing to the terminal:

import (
    "encoding/json"
    "net/http"
)

// GenericQueryHandler wraps any QueryHandler into an HTTP handler
func GenericQueryHandler(handler QueryHandler) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // Parse query parameters from the URL (e.g., /users?name=Alice)
        filter := make(map[string]interface{})
        for key, values := range r.URL.Query() {
            filter[key] = values[0] // Grab the first value for simplicity
        }

        // Execute the query using your handler
        result, err := handler.Execute(filter)
        if err != nil {
            w.WriteHeader(http.StatusInternalServerError)
            json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
            return
        }

        // Send the result as JSON response
        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusOK)
        if err := json.NewEncoder(w).Encode(result); err != nil {
            w.WriteHeader(http.StatusInternalServerError)
            json.NewEncoder(w).Encode(map[string]string{"error": "failed to encode response"})
        }
    }
}

Step 3: Reuse the Handler Across Models

Register routes for different models by passing their respective QueryHandler implementations—no need to rewrite HTTP logic every time:

import "log"

// Example PostQuery implementation (mirrors UserQuery)
type PostQuery struct{}

func (pq *PostQuery) Execute(filter map[string]interface{}) (interface{}, error) {
    posts := []struct {
        ID    int    `json:"id"`
        Title string `json:"title"`
    }{
        {ID: 1, Title: "Go Generics 101"},
        {ID: 2, Title: "Building REST APIs in Go"},
    }
    return posts, nil
}

func main() {
    // Register routes with the generic handler
    http.HandleFunc("/users", GenericQueryHandler(&UserQuery{}))
    http.HandleFunc("/posts", GenericQueryHandler(&PostQuery{}))

    log.Println("Server starting on :8080...")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Bonus: Use Go Generics for Strict Type Safety (Go 1.18+)

If you want to avoid interface{} and enforce type consistency, use generics to define a typed query handler:

import (
    "database/sql"
    "fmt"
)

// GenericTypedQuery handles queries for a specific model type T
type GenericTypedQuery[T any] struct {
    DB        *sql.DB
    TableName string
}

func (q *GenericTypedQuery[T]) Execute(filter map[string]interface{}) ([]T, error) {
    // Write generic SQL logic here (e.g., build WHERE clause from filter)
    // This lets you reuse the same query logic for any model
    rows, err := q.DB.Query(fmt.Sprintf("SELECT * FROM %s", q.TableName))
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var results []T
    // Add logic to scan rows into T instances (you might need a helper for this)
    // For simplicity, this example skips the scan implementation
    return results, nil
}

Pro Tip for Better Search Results

Next time you're looking for resources, try searching for terms like:

  • "Go REST API composition reuse"
  • "Go generic database query handler"
  • "Go reusable HTTP handlers"

These align better with how Go developers talk about this problem, so you'll find more relevant examples and best practices.

内容的提问来源于stack exchange,提问作者sibert

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:59:52