{"id":28718621,"url":"https://github.com/bappasahabapi/go-gin-postgresql-local","last_synced_at":"2026-04-30T16:32:37.393Z","repository":{"id":298366469,"uuid":"999739330","full_name":"bappasahabapi/Go-Gin-PostgreSQL-Local","owner":"bappasahabapi","description":"This project demonstrates how to build a simple REST API using Go with the Gin framework, connecting to a locally installed PostgreSQL database. It includes features like automatic table creation on startup, colored console logging for better readability, and live reloading for an improved development experience.","archived":false,"fork":false,"pushed_at":"2025-06-10T18:20:45.000Z","size":13410,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-10T19:37:55.354Z","etag":null,"topics":["gin","go","postgresql","rest-api"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bappasahabapi.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-10T17:57:39.000Z","updated_at":"2025-06-10T18:20:48.000Z","dependencies_parsed_at":"2025-06-10T19:51:32.896Z","dependency_job_id":null,"html_url":"https://github.com/bappasahabapi/Go-Gin-PostgreSQL-Local","commit_stats":null,"previous_names":["bappasahabapi/go-gin-postgresql-local"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/bappasahabapi/Go-Gin-PostgreSQL-Local","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bappasahabapi%2FGo-Gin-PostgreSQL-Local","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bappasahabapi%2FGo-Gin-PostgreSQL-Local/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bappasahabapi%2FGo-Gin-PostgreSQL-Local/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bappasahabapi%2FGo-Gin-PostgreSQL-Local/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bappasahabapi","download_url":"https://codeload.github.com/bappasahabapi/Go-Gin-PostgreSQL-Local/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bappasahabapi%2FGo-Gin-PostgreSQL-Local/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259924667,"owners_count":22932781,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gin","go","postgresql","rest-api"],"created_at":"2025-06-15T05:01:45.770Z","updated_at":"2026-04-30T16:32:37.363Z","avatar_url":"https://github.com/bappasahabapi.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"Output:\n\n![Items-Api](output.png)\n\n# Run the application\n\n- `go run main.go || air`\n\n# Folder Structure:\n\n```bash\ngo-gin-postgres-local/\n│\n├── controllers/\n│   └── item_controller.go\n│\n├── models/\n│   └── item.go\n│\n├── routes/\n│   └── item_routes.go\n│\n├── config/\n│   └── db.go\n│\n├── main.go\n│\n└── go.mod\n\n\n```\n\n# Go Gin PostgreSQL Local API\n\nThis project demonstrates how to build a simple REST API using Go with the Gin framework, connecting to a locally installed PostgreSQL database. It includes features like automatic table creation on startup, colored console logging for better readability, and live reloading for an improved development experience.\n\n## Features\n\n*   **Connects to a local PostgreSQL database.**\n*   Uses the **Gin framework for routing and request handling.**\n*   Defines a simple `Item` model and CRUD-like API endpoints (`/items`).\n*   **Automatic Table Creation**: The `items` table is created automatically if it doesn't exist when the server starts.\n*   **Colored Console Output**: Important server logs (connection success, server start, Gin messages) are color-coded for easier debugging.\n*   **Live Reloading**: Uses `air` | `gin` to automatically restart the server on code changes.\n\n    - go install github.com/air-verse/air@latest\n    - air\n\n## Prerequisites\n\n\n*   **Go**: Version 1.18 or newer.\n*   **PostgreSQL**: Installed and running locally (not via Docker as per the final setup).\n*   **`air` (for live reload)**: Go live reload tool.\n\n## 1. PostgreSQL Setup (Local Instance)\n\n1.  **Install PostgreSQL** on your operating system if you haven't already.\n2.  Ensure the PostgreSQL service is running.\n3.  Connect to PostgreSQL as a superuser (e.g., `postgres`):\n    ```bash\n    psql -U postgres\n    ```\n4.  Create a database (e.g., `foodie`):\n    ```sql\n    CREATE DATABASE foodie;\n    ```\n5.  Create a user and grant privileges (e.g., user `postgres` with password `postgres` for simplicity in this example, or create a dedicated user):\n    ```sql\n    -- If using the existing 'postgres' user, ensure its password is set or you know it.\n    -- To create a new user:\n    -- CREATE USER myappuser WITH PASSWORD 'securepassword';\n    -- GRANT ALL PRIVILEGES ON DATABASE foodie TO myappuser;\n    ```\n    *For this project, we ended up using the default `postgres` user with password `postgres` and database `foodie`.*\n\n## 2. Go Project Setup\n\n1.  Create a project directory:\n    ```bash\n    mkdir go-gin-postgres-local\n    cd go-gin-postgres-local\n    ```\n\n2.  Initialize Go modules:\n    ```bash\n    go mod init go-gin-postgres-local\n    ```\n\n3.  Get necessary Go packages:\n    ```bash\n    go get github.com/gin-gonic/gin\n    go get github.com/lib/pq  # PostgreSQL driver\n    ```\n\n## 3. Application Code (`main.go`)\n\nCreate a `main.go` file with the following content. This version includes database connection, schema initialization, colored logging, and Gin handlers.\n\n```go\npackage main\n\nimport (\n\t\"database/sql\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/gin-gonic/gin\"\n\t_ \"github.com/lib/pq\" // The PostgreSQL driver\n)\n\n// ANSI Color Codes\nconst (\n\tColorReset  = \"\\033[0m\"\n\tColorGreen  = \"\\033[32m\"\n\tColorYellow = \"\\033[33m\"\n\tColorBlue   = \"\\033[34m\"\n\tColorRed    = \"\\033[31m\"\n)\n\nvar db *sql.DB\n\ntype Item struct {\n\tID       int    `json:\"id\"`\n\tName     string `json:\"name\"`\n\tQuantity int    `json:\"quantity\"`\n}\n\n// Function to initialize the database schema\nfunc initializeSchema(db *sql.DB) error {\n\tcreateTableSQL := `\n\tCREATE TABLE IF NOT EXISTS items (\n\t\tid SERIAL PRIMARY KEY,\n\t\tname VARCHAR(100) NOT NULL,\n\t\tquantity INTEGER\n\t);`\n\t_, err := db.Exec(createTableSQL)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error creating items table: %w\", err)\n\t}\n\tlog.Println(ColorGreen + \"Items table checked/created successfully.\" + ColorReset)\n\treturn nil\n}\n\n// Custom writer to colorize Gin's specific output lines\ntype ginColorWriter struct {\n\twriter io.Writer\n}\n\nfunc (w *ginColorWriter) Write(p []byte) (n int, err error) {\n\ts := string(p)\n\tif strings.Contains(s, \"[GIN-debug] Listening and serving HTTP on\") || strings.Contains(s, \"Listening and serving HTTP on\") {\n\t\ts = ColorGreen + s + ColorReset\n\t} else if strings.Contains(s, \"[GIN-debug] [WARNING]\") {\n\t\ts = ColorYellow + s + ColorReset\n\t} else if strings.Contains(s, \"[GIN-debug] GET\") || strings.Contains(s, \"[GIN-debug] POST\") {\n\t\ts = ColorBlue + s + ColorReset\n\t}\n\treturn w.writer.Write([]byte(s))\n}\n\nfunc main() {\n\tdbHost := getEnv(\"DB_HOST\", \"localhost\")\n\tdbPort := getEnv(\"DB_PORT\", \"5432\")\n\tdbUser := getEnv(\"DB_USER\", \"postgres\")   // Adjusted to 'postgres'\n\tdbPassword := getEnv(\"DB_PASSWORD\", \"postgres\") // Adjusted to 'postgres'\n\tdbName := getEnv(\"DB_NAME\", \"foodie\")     // Adjusted to 'foodie'\n\tsslMode := getEnv(\"DB_SSLMODE\", \"disable\")\n\n\tconnStr := fmt.Sprintf(\"host=%s port=%s user=%s password=%s dbname=%s sslmode=%s\",\n\t\tdbHost, dbPort, dbUser, dbPassword, dbName, sslMode)\n\n\tvar err error\n\tdb, err = sql.Open(\"postgres\", connStr)\n\tif err != nil {\n\t\tlog.Fatalf(ColorRed+\"Error opening database: %v\"+ColorReset, err)\n\t}\n\tdefer db.Close()\n\n\terr = db.Ping()\n\tif err != nil {\n\t\tlog.Fatalf(ColorRed+\"Error connecting to database: %v. Check connection string and if PostgreSQL is running.\"+ColorReset, err)\n\t}\n\tlog.Println(ColorGreen + \"Successfully connected to local PostgreSQL!\" + ColorReset)\n\n\tif err := initializeSchema(db); err != nil {\n\t\tlog.Fatalf(ColorRed+\"Error initializing database schema: %v\"+ColorReset, err)\n\t}\n\n\tcoloredGinDefaultWriter := \u0026ginColorWriter{writer: os.Stdout}\n\tgin.DefaultWriter = coloredGinDefaultWriter\n\t// gin.DefaultErrorWriter = \u0026ginColorWriter{writer: os.Stderr} // Optionally color Gin errors too\n\n\trouter := gin.Default()\n\n\trouter.GET(\"/items\", getItems)\n\trouter.GET(\"/items/:id\", getItem)\n\trouter.POST(\"/items\", createItem)\n\n\tlog.Println(ColorGreen + \"Starting server on :8080\" + ColorReset)\n\tif err := router.Run(\":8080\"); err != nil {\n\t\tlog.Fatalf(ColorRed+\"Failed to run server: %v\"+ColorReset, err)\n\t}\n}\n\nfunc getEnv(key, fallback string) string {\n\tif value, ok := os.LookupEnv(key); ok {\n\t\treturn value\n\t}\n\treturn fallback\n}\n\n// --- Gin Handlers ---\nfunc getItems(c *gin.Context) {\n\trows, err := db.Query(\"SELECT id, name, quantity FROM items\")\n\tif err != nil {\n\t\tlog.Printf(ColorRed+\"Error querying items: %v\"+ColorReset, err)\n\t\tc.JSON(http.StatusInternalServerError, gin.H{\"error\": \"Failed to retrieve items\"})\n\t\treturn\n\t}\n\tdefer rows.Close()\n\titems := []Item{}\n\tfor rows.Next() {\n\t\tvar item Item\n\t\tif err := rows.Scan(\u0026item.ID, \u0026item.Name, \u0026item.Quantity); err != nil {\n\t\t\tlog.Printf(ColorRed+\"Error scanning item row: %v\"+ColorReset, err)\n\t\t\tc.JSON(http.StatusInternalServerError, gin.H{\"error\": \"Failed to process item data\"})\n\t\t\treturn\n\t\t}\n\t\titems = append(items, item)\n\t}\n\tif err = rows.Err(); err != nil {\n\t\tlog.Printf(ColorRed+\"Error after iterating rows: %v\"+ColorReset, err)\n\t\tc.JSON(http.StatusInternalServerError, gin.H{\"error\": \"Error processing item results\"})\n\t\treturn\n\t}\n\tc.JSON(http.StatusOK, items)\n}\n\nfunc getItem(c *gin.Context) {\n\tid := c.Param(\"id\")\n\tvar item Item\n\trow := db.QueryRow(\"SELECT id, name, quantity FROM items WHERE id = $1\", id)\n\terr := row.Scan(\u0026item.ID, \u0026item.Name, \u0026item.Quantity)\n\tif err != nil {\n\t\tif err == sql.ErrNoRows {\n\t\t\tc.JSON(http.StatusNotFound, gin.H{\"error\": \"Item not found\"})\n\t\t} else {\n\t\t\tlog.Printf(ColorRed+\"Error querying single item: %v\"+ColorReset, err)\n\t\t\tc.JSON(http.StatusInternalServerError, gin.H{\"error\": \"Failed to retrieve item\"})\n\t\t}\n\t\treturn\n\t}\n\tc.JSON(http.StatusOK, item)\n}\n\nfunc createItem(c *gin.Context) {\n\tvar newItem Item\n\tif err := c.ShouldBindJSON(\u0026newItem); err != nil {\n\t\tc.JSON(http.StatusBadRequest, gin.H{\"error\": err.Error()})\n\t\treturn\n\t}\n\tif newItem.Name == \"\" {\n\t\tc.JSON(http.StatusBadRequest, gin.H{\"error\": \"Item name cannot be empty\"})\n\t\treturn\n\t}\n\terr := db.QueryRow(\n\t\t\"INSERT INTO items (name, quantity) VALUES ($1, $2) RETURNING id\",\n\t\tnewItem.Name, newItem.Quantity,\n\t).Scan(\u0026newItem.ID)\n\tif err != nil {\n\t\tlog.Printf(ColorRed+\"Error creating item: %v\"+ColorReset, err)\n\t\tc.JSON(http.StatusInternalServerError, gin.H{\"error\": \"Failed to create item\"})\n\t\treturn\n\t}\n\tc.JSON(http.StatusCreated, newItem)\n}","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbappasahabapi%2Fgo-gin-postgresql-local","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbappasahabapi%2Fgo-gin-postgresql-local","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbappasahabapi%2Fgo-gin-postgresql-local/lists"}