I am trying to do a REST API in Go. The query works when placed within the main handler (shows in terminal), but gives error in the browser when moved to the desired handler.
localhost:8080/ <------ Browser gives an error (not showing anything) and the terminal shows several error messages - one of them is:
http: panic serving [::1]:51100: runtime error: invalid memory address or nil pointer dereference
localhost:8080/getuser <---gives correct response
Getuser
package main
import (
"fmt"
"log"
"net/http"
"database/sql"
_ "github.com/lib/pq"
)
const (
host = "127.0.0.1"
port = 5432
user = "test"
password = "pw"
dbname = "Test"
)
var db *sql.DB
type User struct {
USER_ID string
USER_NAME string
}
func handleRequests() {
http.HandleFunc("/", index)
http.HandleFunc("/getuser", Getuser)
}
func index(w http.ResponseWriter, r *http.Request){
rows, err := db.Query(`SELECT "USER_ID","USER_NAME" FROM users`)
if err != nil {
http.Error(w, http.StatusText(500), 500)
return
}
defer rows.Close()
for rows.Next() {
user := User{}
err := rows.Scan(&user.USER_ID, &user.USER_NAME)
if err != nil {
http.Error(w, http.StatusText(500), 500)
}
fmt.Fprintf(w, "%s, %s
", user.USER_ID, user.USER_NAME)
}
}
func Getuser(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Getuser") // <-------------------------this works!
}
func main() {
handleRequests()
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=require",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatalln(err)
}
if err != nil {
panic(err)
}
defer db.Close()
err = db.Ping()
if err != nil {
panic(err)
}
log.Fatal(http.ListenAndServe(":8080", nil))
}
EDIT
The complete error list in terminal
created by net/http.(*Server).Serve /usr/local/go/src/net/http/server.go:2795 +0x27b 2018/03/23 08:36:39 http: panic serving [::1]:51390: runtime error: invalid memory address or nil pointer dereference goroutine 36 [running]: net/http.(*conn).serve.func1(0xc4201d80a0) /usr/local/go/src/net/http/server.go:1726 +0xd0 panic(0x1294460, 0x1471840) /usr/local/go/src/runtime/panic.go:505 +0x229 database/sql.(*DB).conn(0x0, 0x13277e0, 0xc42009e020, 0xc420028f01, 0xc4200a0218, 0xc4200a0220, 0xc4201e8b01) /usr/local/go/src/database/sql/sql.go:1015 +0x3a database/sql.(*DB).query(0x0, 0x13277e0, 0xc42009e020, 0x12f7553, 0x26, 0x0, 0x0, 0x0, 0x12ec601, 0x8, ...) /usr/local/go/src/database/sql/sql.go:1437 +0x66
database/sql.(*DB).QueryContext(0x0, 0x13277e0, 0xc42009e020, 0x12f7553, 0x26, 0x0, 0x0, 0x0, 0x10825ed, 0xc4201d0180, ...) /usr/local/go/src/database/sql/sql.go:1419 +0xd2 database/sql.(*DB).Query(0x0, 0x12f7553, 0x26, 0x0, 0x0, 0x0, 0xc4201ec070, 0x8000000000000000, 0x0) /usr/local/go/src/database/sql/sql.go:1433 +0x82 main.Getsign(0x13275a0, 0xc4202020e0, 0xc4201f4100) /Users/sibert/go/src/main/api.go:55 +0x65 net/http.HandlerFunc.ServeHTTP(0x1302020, 0x13275a0, 0xc4202020e0, 0xc4201f4100) /usr/local/go/src/net/http/server.go:1947 +0x44 net/http.(*ServeMux).ServeHTTP(0x147cc00, 0x13275a0, 0xc4202020e0, 0xc4201f4100) /usr/local/go/src/net/http/server.go:2337 +0x130 net/http.serverHandler.ServeHTTP(0xc42009b2b0, 0x13275a0, 0xc4202020e0, 0xc4201f4100) /usr/local/go/src/net/http/server.go:2694 +0xbc net/http.(*conn).serve(0xc4201d80a0, 0x13277a0, 0xc4201b4280) /usr/local/go/src/net/http/server.go:1830 +0x651 created by net/http.(*Server).Serve /usr/local/go/src/net/http/server.go:2795 +0x27b 2018/03/23 08:36:39 http: panic serving [::1]:51391: runtime error: invalid memory address or nil pointer dereference goroutine 24 [running]: net/http.(*conn).serve.func1(0xc4200b4b40) /usr/local/go/src/net/http/server.go:1726 +0xd0 panic(0x1294460, 0x1471840) /usr/local/go/src/runtime/panic.go:505 +0x229 database/sql.(*DB).conn(0x0, 0x13277e0, 0xc42009e020, 0xc420024501, 0xc4200a0318, 0xc4200a0320, 0xc420052b01) /usr/local/go/src/database/sql/sql.go:1015 +0x3a database/sql.(*DB).query(0x0, 0x13277e0, 0xc42009e020, 0x12f7553, 0x26, 0x0, 0x0, 0x0, 0x12ec601, 0x8, ...) /usr/local/go/src/database/sql/sql.go:1437 +0x66 database/sql.(*DB).QueryContext(0x0, 0x13277e0, 0xc42009e020, 0x12f7553, 0x26, 0x0, 0x0, 0x0, 0x10825ed, 0xc420140480, ...) /usr/local/go/src/database/sql/sql.go:1419 +0xd2 database/sql.(*DB).Query(0x0, 0x12f7553, 0x26, 0x0, 0x0, 0x0, 0xc42009eb10, 0x8000000000000000, 0x0) /usr/local/go/src/database/sql/sql.go:1433 +0x82 main.Getsign(0x13275a0, 0xc42019e0e0, 0xc42019a300) /Users/sibert/go/src/main/api.go:55 +0x65 net/http.HandlerFunc.ServeHTTP(0x1302020, 0x13275a0, 0xc42019e0e0, 0xc42019a300) /usr/local/go/src/net/http/server.go:1947 +0x44 net/http.(*ServeMux).ServeHTTP(0x147cc00, 0x13275a0, 0xc42019e0e0, 0xc42019a300) /usr/local/go/src/net/http/server.go:2337 +0x130 net/http.serverHandler.ServeHTTP(0xc42009b2b0, 0x13275a0, 0xc42019e0e0, 0xc42019a300) /usr/local/go/src/net/http/server.go:2694 +0xbc net/http.(*conn).serve(0xc4200b4b40, 0x13277a0, 0xc4200a0780) /usr/local/go/src/net/http/server.go:1830 +0x651 created by net/http.(*Server).Serve /usr/local/go/src/net/http/server.go:2795 +0x27b
What you are encountering is the classic case of variable shadowing.
The :=
creates a new db
variable that shadows your package level db
variable. The set value of db
only exists within the scope of your main function while your package level db
variable remains as a nil pointer, thus when you attempt to perform a method call on nil
, in your index handler, you get a panic.
The reason your Getuser handler works has nothing to do with the DefaultServeMux it's simply because you aren't attempting to access a member function on a nil value.
The way to fix this is within your main function to predeclare the err
variable and change the :=
to simple assignment =
func main() {
// ...
var err error
// this will now correctly set your package level variable
db, err = sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatalln(err)
}
// ...
}