May 31, 2025 10:19 PM (GMT+6)

Okay. so the last work I did which I didn’t write in my log is I separated the RootHandler from my main.go.

This is how my main.go looks like right now :

package main

import (
	rootrequesthandler "backend/root_request_handler"
	"database/sql"
	"fmt"
	"log"
	"net/http"

	_ "github.com/lib/pq"
)

var port string = ":8080"
var db *sql.DB

func initalizeDB() *sql.DB {
	connStr := "host=localhost port=5432 user=tamim password=tamim dbname=backend sslmode=disable"

	db, err := sql.Open("postgres", connStr)
	if err != nil {
		log.Fatal(err)
	}

	err = db.Ping()
	if err != nil {
		log.Fatal("Could not connect:", err)
	}

	fmt.Println("Connected to PostgreSQL!")

	return db
}

func main() {
	db = initalizeDB()

	defer db.Close()

	mux := http.NewServeMux()
	mux.Handle("/", &rootrequesthandler.RootRequestHandler{})

	log.Fatal(http.ListenAndServe(port, mux))
}

func init() {
	fmt.Println("Initalizing server..")
	fmt.Printf("serving at : <http://localhost>%s\\n", port)
}

And here’s my rootRequestHandler

package rootrequesthandler

import (
	"fmt"
	"net/http"
)

type RootRequestHandler struct{}

func (rqh *RootRequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		rqh.handleGET(w)
	case http.MethodPost:
		rqh.handlePOST(w)
	}
}

func (rqh *RootRequestHandler) handleGET(w http.ResponseWriter) {
	fmt.Fprintf(w, "Hello, world from get method")
}

func (rqh *RootRequestHandler) handlePOST(w http.ResponseWriter) {
	fmt.Fprintf(w, "Hello, world from POST")
}

The pattern I'm exploring here is similar to interface classes in other languages like Dart. In functional programming languages like Go, this pattern manifests as having specific function implementations.

Let me show you an example:

when using Handle instead of HandlerFunc like this

mux.Handle("/", &rootrequesthandler.RootRequestHandler{})

The type must have a ServeHTTP function.

package rootrequesthandler

import (
	...
)

type RootRequestHandler struct{}

func (rqh *RootRequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case http.MethodGet:
		rqh.handleGET(w)
	case http.MethodPost:
		rqh.handlePOST(w)
	}
}

...

That’s simple ! anyways let’s continue

I want to extract the db functionality too. so I did something like

May 31, 2025 10:38 PM (GMT+6)

package dbhandler

import (
	"database/sql"
	"fmt"
	"log"
)

var db *sql.DB

func GetDB() *sql.DB {
	if db == nil {
		db = initalizeDB()
		return db
	}
	return db
}

func initalizeDB() *sql.DB {
	connStr := "host=localhost port=5432 user=tamim password=tamim dbname=backend sslmode=disable"

	db, err := sql.Open("postgres", connStr)
	if err != nil {
		log.Fatal(err)
	}

	err = db.Ping()
	if err != nil {
		log.Fatal("Could not connect:", err)
	}

	fmt.Println("Connected to PostgreSQL!")

	return db
}

I'm not sure if this will work as intended - I'm aiming for a lazy singleton pattern here. Moving on.

I've updated the DB service to use GORM since writing SQL queries manually isn't ideal for me. As someone new to backend development, using an ORM makes database handling much more manageable.

Here's how my main.go looks now

package main

import (
	dbhandler "backend/db_handler"
	rootrequesthandler "backend/root_request_handler"

	"fmt"
	"log"
	"net/http"

	_ "github.com/lib/pq"
)

var port string = ":8080"

func main() {
	dbhandler.InitalizeDB()

	mux := http.NewServeMux()
	mux.Handle("/", &rootrequesthandler.RootRequestHandler{})

	log.Fatal(http.ListenAndServe(port, mux))
}

func init() {
	fmt.Println("Initalizing server..")
	fmt.Printf("serving at : <http://localhost>%s\\n", port)
}