So fazendo essa publicacao para mostrar como esta ficando o projeto que estou fazendo com o curso, e dizer que estou gostando, aprendi bastante coisa ate. Tomei conhecimento de coisas como connections com DataBase em Go, aprendi sobre sistema de .env variavies de ambiente, e algo muito bom, pois assim evita de eu por coisas sensiveis como nomes e senhas de bancos no projeto em si, ele fica salvo num arquivo externo do projeto e isso tambem da mais modularidade e praticidade na hora de estabelecer connections, pois da para mudar tudo sem precisa ter de recopilar o projeto inteiro.
Assim esta o codigo ate entao:
Main
package main
import (
"github.com/rickmvi/web-service/internal/product"
"net/http"
)
func main() {
http.HandleFunc("/", product.HandleProducts)
if err := http.ListenAndServe(":3000", nil); err != nil {
panic(err)
}
}
Product
package product
import (
"github.com/rickmvi/web-service/internal/database/postgresql"
"html/template"
"net/http"
)
var (
Template = template.Must(template.ParseGlob("./static/*.html"))
)
type Product struct {
Id int
Name string
Description string
Price float64
Quantity int
}
// HandleProducts handles HTTP requests to the root route, retrieves products from the database, and renders the handleProducts.html template.
func HandleProducts(w http.ResponseWriter, r *http.Request) {
db := postgresql.Connection()
getProducts, err := db.Query("select * from products")
checkError(err)
p := Product{}
var products []Product
for getProducts.Next() {
id, quantity, name, description, price := productField()
err = getProducts.Scan(&id, &name, &description, &price, &quantity)
checkError(err)
populateProduct(&p, id, name, description, price, quantity)
products = append(products, p)
}
if err := Template.ExecuteTemplate(w, "index.html", products); err != nil {
panic(err)
}
postgresql.Close(db)
}
// populateProduct populates a Product struct by assigning provided values for id, name, description, price, and quantity.
func populateProduct(p *Product, id *int, name *string, description *string, price *float64, quantity *int) {
p.Id = *id
p.Name = *name
p.Description = *description
p.Price = *price
p.Quantity = *quantity
}
// productField initializes and returns pointers to product fields: id, quantity, name, description, and price.
func productField() (*int, *int, *string, *string, *float64) {
var id, quantity int
var name, description string
var price float64
return &id, &quantity, &name, &description, &price
}
// checkError checks if the provided error is non-nil and triggers a panic if it is.
func checkError(err error) {
if err != nil {
panic(err)
}
}
Database/Postgreslq
package postgresql
import (
"database/sql"
"fmt"
"os"
"github.com/joho/godotenv"
_ "github.com/lib/pq"
)
// init initializes the environment by loading variables from a .env file and checks for any loading errors.
func init() {
err := godotenv.Load()
checkError(err)
}
// checkError verifies if an error exists and panics if it is not nil. Use it to handle unexpected errors gracefully.
func checkError(err any) {
if err != nil {
panic(err)
}
}
// Connection establishes a connection to a PostgreSQL database using environment variables and returns a *sql.DB instance.
// It panics if required environment variables are missing or if the connection fails.
func Connection() *sql.DB {
host := os.Getenv("DB_HOST")
port := os.Getenv("DB_PORT")
user := os.Getenv("DB_USER")
password := os.Getenv("DB_PASSWORD")
dbname := os.Getenv("DB_NAME")
sslmode := os.Getenv("DB_SSLMODE")
if user == "" || password == "" || dbname == "" {
panic("Missing environment variables")
}
conn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s", host, port, user, password, dbname, sslmode)
db, err := sql.Open("postgres", conn)
checkError(err)
err = db.Ping()
if err != nil {
panic(fmt.Sprintf("Unable to connect to the database: %s", err))
}
fmt.Println("Connection with PostgreSQL established successfully")
return db
}
// Close safely terminates the connection to the database, ensuring any errors during closure are handled appropriately.
func Close(db *sql.DB) {
defer func(db *sql.DB) {
err := db.Close()
checkError(err)
}(db)
err := db.Close()
if err != nil {
panic(fmt.Sprintf("Unable to close the database connection: %s", err))
}
}
Estrutura do Projeto