Skip to content

Instantly share code, notes, and snippets.

@ScaferuZ
Created May 28, 2025 03:55
Show Gist options
  • Save ScaferuZ/2de9b71efc227e359ec7ddc8f318b864 to your computer and use it in GitHub Desktop.
Save ScaferuZ/2de9b71efc227e359ec7ddc8f318b864 to your computer and use it in GitHub Desktop.
package main
import (
"database/sql"
"fmt"
"html/template"
"log"
"net/http"
"os"
_ "github.com/lib/pq"
)
type Counter struct {
ID int `json:"id"`
Count int `json:"count"`
}
var db *sql.DB
var tmpl *template.Template
func main() {
// Initialize database connection
initDB()
// Initialize template
tmpl = template.Must(template.ParseGlob("templates/*.html"))
// Routes
http.HandleFunc("/", homeHandler)
http.HandleFunc("/increment", incrementHandler)
http.HandleFunc("/decrement", decrementHandler)
http.HandleFunc("/reset", resetHandler)
http.HandleFunc("/health", healthHandler)
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
log.Printf("Server starting on port %s", port)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
func initDB() {
// Database connection string
dbHost := os.Getenv("DB_HOST")
if dbHost == "" {
dbHost = "localhost"
}
dbUser := os.Getenv("DB_USER")
if dbUser == "" {
dbUser = "postgres"
}
dbPassword := os.Getenv("DB_PASSWORD")
if dbPassword == "" {
dbPassword = "password"
}
dbName := os.Getenv("DB_NAME")
if dbName == "" {
dbName = "counter_app"
}
dbPort := os.Getenv("DB_PORT")
if dbPort == "" {
dbPort = "5432"
}
connStr := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable",
dbHost, dbPort, dbUser, dbPassword, dbName)
var err error
db, err = sql.Open("postgres", connStr)
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
// Test connection
if err = db.Ping(); err != nil {
log.Fatal("Failed to ping database:", err)
}
log.Println("Connected to database successfully")
// Create table if it doesn't exist
createTable()
// Initialize counter if it doesn't exist
initCounter()
}
func createTable() {
query := `
CREATE TABLE IF NOT EXISTS counters (
id SERIAL PRIMARY KEY,
count INTEGER NOT NULL DEFAULT 0
)`
_, err := db.Exec(query)
if err != nil {
log.Fatal("Failed to create table:", err)
}
log.Println("Table created or already exists")
}
func initCounter() {
var count int
err := db.QueryRow("SELECT COUNT(*) FROM counters").Scan(&count)
if err != nil {
log.Fatal("Failed to check counter:", err)
}
if count == 0 {
_, err = db.Exec("INSERT INTO counters (count) VALUES (0)")
if err != nil {
log.Fatal("Failed to initialize counter:", err)
}
log.Println("Counter initialized")
}
}
func getCurrentCount() int {
var count int
err := db.QueryRow("SELECT count FROM counters WHERE id = 1").Scan(&count)
if err != nil {
log.Printf("Error getting count: %v", err)
return 0
}
return count
}
func updateCount(newCount int) error {
_, err := db.Exec("UPDATE counters SET count = $1 WHERE id = 1", newCount)
return err
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
count := getCurrentCount()
data := Counter{ID: 1, Count: count}
err := tmpl.ExecuteTemplate(w, "index.html", data)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
func incrementHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
currentCount := getCurrentCount()
newCount := currentCount + 1
err := updateCount(newCount)
if err != nil {
http.Error(w, "Failed to update counter", http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func decrementHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
currentCount := getCurrentCount()
newCount := currentCount - 1
err := updateCount(newCount)
if err != nil {
http.Error(w, "Failed to update counter", http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func resetHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
err := updateCount(0)
if err != nil {
http.Error(w, "Failed to reset counter", http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
// Check database connection
if err := db.Ping(); err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprintf(w, "Database connection failed: %v", err)
return
}
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, "OK")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment