Search code examples
functiongohandler

Learning Go: How to use http.HandlerFunc?


Trying To Learn Go

My Test Project

I am building a simple API to communicate with a light SQL database.
I created this function, that gets all hosts from the DB table.
As I understand, my function should take a pointer to the DB and return me http.HandlerFunc.

func (h HostController) GetAllHosts(db *sql.DB) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var host entities.Host
        var hosts []entities.Host
        var errorMessage entities.Error
        rows, err := db.Query("SELECT * FROM hosts WHERE hosts = ?", host)
        if err != nil {
            errorMessage.Message = "Error: Get all hosts"
            utils.SendError(w, http.StatusInternalServerError, errorMessage)
            return
        }
        defer rows.Close()
        for rows.Next() {
            err := rows.Scan(&host.ID, &host.Uuid, &host.Name, &host.IPAddress)
            if err != nil {
                errorMessage.Message = "Error: (Get all hosts) Can't scan rows"
                utils.SendError(w, http.StatusInternalServerError, errorMessage)
                return
            }
            hosts = append(hosts, host)
        }
        ////If hosts slice is empty -> no data in database
        if len(hosts) == 0 {
            errorMessage.Message = "No found hosts in database"
            utils.SendError(w, http.StatusInternalServerError, errorMessage)
            return
        }
        //Convert containers content to JSON representation
        w.Header().Set("Content-Type", "application/json")
        utils.SendSuccess(w, hosts)
    }
}

Now, Until here everything should be good, but I don't know how to implement this on main.go build layout:

.
├── controllers
│       └── hostcontroller.go
│       
└── main.go

and this is how I am trying to implement it on the main.go

package main

import (
    "examProg/config"
    "examProg/controllers"
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/mux"
    _ "github.com/mattn/go-sqlite3"
)

func main() {
    db := config.GetDB() //Establishing connection to DBase
    {

        router := mux.NewRouter()

        router.Handle("/host", controllers.HostController.GetAllHosts(db))

        fmt.Println("Server is running at port: 2030")
        log.Println("Server Running OK | Port: 2030")
        log.Fatal(http.ListenAndServe(":2030", router))
    }

}

I don't understand how to implement the http.HandlerFunc 🙃


Solution

  • The expression controllers.HostController.GetAllHosts is a method expression. The result of a method expression is a function that, in addition to the method's argument's, takes an instance of the receiver's type as its first argument.

    Hence the "not enough arguments in call ..." error.

    To illustrate:

    f := controllers.HostController.GetAllHosts
    fmt.Println(reflect.TypeOf(f))
    // output: func(controllers.HostController, *sql.DB)
    

    So, to make the code compile, you need to pass an instance of controllers.HostController to the call, i.e.

    controllers.HostController.GetAllHosts(controllers.HostController{}, db)
    

    As you can see, it ain't pretty. Method expressions have their use, I'm sure, but I haven't encountered them much. What I see most often instead, is the use of method values.

    h := controllers.HostController{}
    router.Handle("/host", h.GetAllHosts(db))