help

140 views
Skip to first unread message

Pilar Garcia

unread,
Feb 17, 2024, 5:38:22 PMFeb 17
to golang-nuts
hi everyone. my name is pilar. im trying to learn coding for the first time in my life......im sooooo lost can anyone let me know how to even begin on this mission......... please any advise will be greatly appreciated..... you folks have a great day cant waint to hear from ya

Sunday Ajayi

unread,
Feb 17, 2024, 11:55:13 PMFeb 17
to golang-nuts
Hi guys, 
Please I am having a little issue with my go project using docker.

I set up my Postgres db in docker with my go app but it is unable to connect. Please what could be the issue?

I will share the docker-compose file and the main.go here

main.go

package main

import (
"database/sql"
"encoding/json"
"log"
"net/http"
"os"

)

type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}

var db *sql.DB
var err error

func main() {
//connect to database
db, err = sql.Open("postgres", os.Getenv("DATABASE_URL"))
log.Println("DATABASE_URL:", os.Getenv("DATABASE_URL"))

if err != nil {
log.Fatal("Error connecting to database: ", err)
}
if db != nil {
log.Println("Database connected")
}
if err := db.Ping(); err != nil {
log.Fatal("Error pinging database: ", err)
}

defer db.Close()

//create the table if it doesn't exist
_, err = db.Exec("CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT, email TEXT)")

if err != nil {
log.Fatal("Error creating table: ", err)
}

//create router
router := mux.NewRouter()
router.HandleFunc("/users", getUsers(db)).Methods("GET")
router.HandleFunc("/users/{id}", getUser(db)).Methods("GET")
router.HandleFunc("/users", createUser(db)).Methods("POST")
router.HandleFunc("/users/{id}", updateUser(db)).Methods("PUT")
router.HandleFunc("/users/{id}", deleteUser(db)).Methods("DELETE")

//start server
log.Fatal(http.ListenAndServe(":8088", jsonContentTypeMiddleware(router)))
}

func jsonContentTypeMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
next.ServeHTTP(w, r)
})
}

// get all users
func getUsers(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
rows, err := db.Query("SELECT * FROM users")
if err != nil {
log.Fatal(err)
}
defer rows.Close()

users := []User{}
for rows.Next() {
var u User
if err := rows.Scan(&u.ID, &u.Name, &u.Email); err != nil {
log.Fatal(err)
}
users = append(users, u)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}

json.NewEncoder(w).Encode(users)
}
}

// get user by id
func getUser(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]

var u User
err := db.QueryRow("SELECT * FROM users WHERE id = $1", id).Scan(&u.ID, &u.Name, &u.Email)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}

json.NewEncoder(w).Encode(u)
}
}

// create user
func createUser(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var u User
json.NewDecoder(r.Body).Decode(&u)

err := db.QueryRow("INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id", u.Name, u.Email).Scan(&u.ID)
if err != nil {
log.Fatal(err)
}

json.NewEncoder(w).Encode(u)
}
}

// update user
func updateUser(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var u User
json.NewDecoder(r.Body).Decode(&u)

vars := mux.Vars(r)
id := vars["id"]

_, err := db.Exec("UPDATE users SET name = $1, email = $2 WHERE id = $3", u.Name, u.Email, id)
if err != nil {
log.Fatal(err)
}

json.NewEncoder(w).Encode(u)
}
}

// delete user
func deleteUser(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]

var u User
err := db.QueryRow("SELECT * FROM users WHERE id = $1", id).Scan(&u.ID, &u.Name, &u.Email)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
} else {
_, err := db.Exec("DELETE FROM users WHERE id = $1", id)
if err != nil {
//todo : fix error handling
w.WriteHeader(http.StatusNotFound)
return
}

json.NewEncoder(w).Encode("User deleted")
}
}
}


Docker compose file:

version: '3.9'

services:
go-app:
container_name: go-app
image: sunnex/go-app:1.0.0
build: .
environment:
- DATABASE_URL="host=go_db port=5432 user=postgres password=postgres dbname=go_db sslmode=disable"
ports:
- "8088:8088"
networks:
- backend
depends_on:
- go_db
go_db:
container_name: go_db
image: postgres:13
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: go_db
ports:
- "5432:5432"
networks:
- backend
volumes:
- pgdata:/var/lib/postgresql/data

volumes:
pgdata: {}

networks:
backend:
driver: bridge

Keep getting this error:
Error pinging database: dial tcp 127.0.0.1:5432: connect: connection refused


Please where am I getting it wrong?

Regards




On Sat, Feb 17, 2024 at 11:38 PM Pilar Garcia <protot...@gmail.com> wrote:
hi everyone. my name is pilar. im trying to learn coding for the first time in my life......im sooooo lost can anyone let me know how to even begin on this mission......... please any advise will be greatly appreciated..... you folks have a great day cant waint to hear from ya

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/9b1fee4f-919f-4bee-a7f0-2fe2ae685542n%40googlegroups.com.

Luca Pascali

unread,
Feb 18, 2024, 4:28:10 AMFeb 18
to Sunday Ajayi, golang-nuts
Hi.

Error says that the connection string that is executed is pointing to TCP 127.0.0.1:5432
from your docker compose file there is no such string, you are correctly using go_db host name to work inside the docker network.

So my guess is that you are not executing what you think you are executing

3 hypotesis:
+ in the docker image that is created for app you are launching a bash file that overrides the environment variable (easy to find: look at the content and look for 127.0.0.1 or DATABASE_URL)
+ you introduced the environment variable and just forgot to rebuild the container (can happen, it happens, no shame)
+ the real code tries to connect (probably somewhere else) to 127.0.0.1 in a block of code that you forgot to cancel/delete/modify to use environment variables

If launched manually, it honors the environment variable. At least the block of code you posted.
So my thoughts are that there's something around it or in the real code

Hope that this can help

Suggestion: put a dependency clause, to be sure to start db before the app, and consider some retries.
DB does not start immediately. It can run some more task at power on that can delay the effective startup by some seconds.

Usually you say that go_db must be started before starting go_app and inside go_app you try multiple times (or retry if db shuts down and restarts during the app execution), but this depends on the type of application you are writing.
24/7 application should (I would say "must") consider some db downtime without crashing. Personal home application can be less refined.

PSK

Steven Hartland

unread,
Feb 18, 2024, 4:57:20 AMFeb 18
to Sunday Ajayi, golang-nuts
What’s your DATABASE_URL? If your on Windows make sure you use localhost not 127.0.0.1 as they aren’t necessarily the same thing  

Brian Candler

unread,
Feb 18, 2024, 5:31:53 AMFeb 18
to golang-nuts
Your code includes this line:
log.Println("DATABASE_URL:", os.Getenv("DATABASE_URL"))
What does the log message actually show? This will confirm whether the environment variable is being passed correctly or not.

I note you are using a different YAML structure for "environment" under go_app than under go_db. The first uses a list, the second uses a map. However, the compose v3 spec says that both are fine: https://docs.docker.com/compose/compose-file/compose-file-v3/#environment

To be sure, you could try

environment:
DATABASE_URL: "host=go_db port=5432 user=postgres password=postgres dbname=go_db sslmode=disable"

Reply all
Reply to author
Forward
0 new messages