I am trying to connect to a database, but getting an error when I make a curl request to the endpoint with the GET
method. I double-checked with the user credentials and have granted full privileges and superuser permissions.
Following is the error I get when curl the endpoint:
santosh@pkg*$:curl -i localhost:8080/books/show
HTTP/1.1 303 See Other
Content-Type: text/html; charset=utf-8
Location: /books
Date: Sat, 19 Nov 2022 12:09:52 GMT
Content-Length: 33
<a href="/books">See Other</a>.
The connection is established with the Database, when the request is made to the database these errors are triggered:
santosh@pkg*$:go run main.go
Database connection successful.
2022/11/19 17:39:47 http: panic serving 127.0.0.1:44324: runtime error: invalid memory address or nil pointer dereference
goroutine 35 [running]:
net/http.(*conn).serve.func1()
/usr/local/go/src/net/http/server.go:1850 0xbf
panic({0x6960e0, 0x8e5630})
/usr/local/go/src/runtime/panic.go:890 0x262
database/sql.(*DB).conn(0x0, {0x7593d0, 0xc00011a000}, 0x1)
/usr/local/go/src/database/sql/sql.go:1288 0x53
database/sql.(*DB).query(0x6?, {0x7593d0, 0xc00011a000}, {0x6da967, 0x13}, {0x0, 0x0, 0x0}, 0x68?)
The main program:
var db *sql.DB
type Books struct {
Isbn string
Title string
Author string
Price float32
}
func init() {
var err error
args := fmt.Sprintf("host=%s port=%d dbname=%s user='%s' password=%s sslmode=%s", "localhost", 5432, "bookstore", "santosh", "dts123", "disable")
db, err := sql.Open("postgres", args)
if err != nil {
fmt.Printf("Creating Database %s", err)
}
if err = db.Ping(); err != nil {
panic(err)
}
fmt.Println("Database connection succussful.")
}
func main() {
http.HandleFunc("/", index)
http.HandleFunc("/books", booksIndex)
http.ListenAndServe(":8080", nil)
}
func index(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/books", http.StatusSeeOther)
}
func booksIndex(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
http.Error(w, http.StatusText(405), http.StatusMethodNotAllowed)
return
}
rows, err := db.Query("SELECT * FROM books")
if err != nil {
http.Error(w, http.StatusText(500), 500)
return
}
defer rows.Close()
bks := make([]Books, 0)
for rows.Next() {
bk := Books{}
err := rows.Scan(&bk.Isbn, &bk.Title, &bk.Author, &bk.Price)
if err != nil {
http.Error(w, http.StatusText(500), 500)
return
}
bks = append(bks, bk)
}
if err = rows.Err(); err != nil {
http.Error(w, http.StatusText(500), 500)
return
}
}
I tried double-checking user privileges and database format and for order. All are in line with the code. The connection is established but fails with panic while querying the DB.
CodePudding user response:
You are not properly initializing the package-level db
variable.
The :=
operator, called "short variable declaration", declares and initializes a new variable in its block scope. Any variable with the same name in an outer scope will be "shadowed".
To properly initialize the package-level variable you can use plain assignment:
var db *sql.DB
func init() {
args := fmt.Sprintf("host=%s port=%d dbname=%s user='%s' password=%s sslmode=%s", "localhost", 5432, "bookstore", "santosh", "dts123", "disable")
var err error
db, err = sql.Open("postgres", args)
if err != nil {
fmt.Printf("Creating Database %s", err)
}
// ...
}
Or you can use :=
but then use a different variable name and make sure to use that for the assignment:
var db *sql.DB
func init() {
args := fmt.Sprintf("host=%s port=%d dbname=%s user='%s' password=%s sslmode=%s", "localhost", 5432, "bookstore", "santosh", "dts123", "disable")
_db, err := sql.Open("postgres", args)
if err != nil {
fmt.Printf("Creating Database %s", err)
}
// ...
db = _db // set "global"
}