Golang. Настройка сервера к api запросам

подскажите, можно ли создать функцию которая будет автоматически проставлять стандартные заголовки, к примеру если у меня идёт обработка по адресу /api

http.HandleFunc("/api/count_users", countUsersHandler) 
http.HandleFunc("/api/count_payments", countPaymentsHandler) 
http.HandleFunc("/api/average_payments", averagePaymentHandler)

То во всех случаях нужно в каждой функции прописывать заголовки:

w.Header().Set("Access-Control-Allow-Origin", "*") 
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
w.Header().Set("Content-Type", "application/json")

А также во всех случаях нужно конвертировать в json:

json.NewEncoder(w).Encode(response)

Можно ли создать функцию к примеру API и просто при каждом запросе на api автоматически это всё проставлять? Вот так:

func countPaymentsHandler(w http.ResponseWriter, r *http.Request) { 
    var count int 
    err := db.QueryRow("SELECT COUNT(*) FROM payments WHERE `status` = '1'").Scan(&count) 
    if err != nil { 
        http.Error(w, "Ошибка при выполнении запроса", http.StatusInternalServerError) 
        return 
    } 

    response := map[string]int{"count": count} 
    return response 
} 

func API(pattern string, handler func()) { 
    http.HandleFunc("/api/"+pattern, func(w http.ResponseWriter, r *http.Request) { 
        w.Header().Set("Access-Control-Allow-Origin", "*") 
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type") 

        response := handler 
        w.Header().Set("Content-Type", "application/json") 
        json.NewEncoder(w).Encode(response) 
    }) 
} 

func main() { 
    initDB() 
    defer db.Close() 

    API("count_payments", countPaymentsHandler) 

    fmt.Println("Сервер запущен на http://localhost:8080") 
    log.Fatal(http.ListenAndServe(":8080", nil)) 
}

Ответы (1 шт):

Автор решения: Алексей

Я обычно делаю с помощью middleware - прослойка между http сервером и обработчиком. Вот так примерно это выглядит:

// mw - сокращение middleware
func mw(handler http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
        w.Header().Set("Content-Type", "application/json")

        handler(w, r)
    }
}

func handler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte(`{"a": 123}`))
}

func main() {
    http.HandleFunc("/path", mw(handler))

    if err := http.ListenAndServe("127.0.0.1:8080", nil); err != nil {
        log.Fatal(err)
    }
}

Естественно mw можно переименовать в какой-нибудь SetApiHeaders и вынести в пакет middlewares. Также можно использовать несколько прослоек на 1 обработчик: http.HandleFunc("/path", SetStandartsHeaders(SetApiHeaders(handler)))

→ Ссылка