Skip to main content
Background Image
  1. Posts/

Go: Building a Simple Web Backend

··454 words·3 mins· loading · loading ·
yuzjing
Author
yuzjing
Table of Contents

🌐 Project Goal
#

Build a simple web service using the Gin framework.

🛠️ Project Structure
#

 1todo-api/
 2├── main.go                 # Entrypoint file
 3├── routes/
 4│   └── todo_routes.go    # Route definitions
 5├── models/
 6│   └── todo.go           # Data structure
 7├── middleware/
 8│   └── logging.go        # Custom middleware
 9├── config/
10│   └── config.go         # Configuration management
11└── go.mod                # Go module

📦 Install Dependencies
#

1go mod init todo-api
2go get -u github.com/gin-gonic/gin
3go get -u github.com/jackc/pgx/v4

🧪 Code Examples
#

1. Configuration Management (config/config.go)
#

 1package config
 2
 3import "github.com/joho/godotenv"
 4
 5func LoadEnv() {
 6    err := godotenv.Load()
 7    if err != nil {
 8        panic("Error loading .env file")
 9    }
10}

2. Database Connection (main.go)
#

 1package main
 2
 3import (
 4    "context"
 5    "fmt"
 6    "log"
 7    "os" // Make sure to import os to use os.Getenv()
 8    "github.com/gin-gonic/gin"
 9    "github.com/jackc/pgx/v4"
10    "todo-api/config"
11    "todo-api/routes"
12)
13
14type Todo struct {
15    ID    int    `json:"id"`
16    Title string `json:"title"`
17}
18
19func main() {
20    // 1. Load environment variables
21    config.LoadEnv()
22
23    // 2. Connect to PostgreSQL
24    connStr := fmt.Sprintf(
25        "postgres://%s:%s@%s:%s/%s?sslmode=disable",
26        os.Getenv("DB_USER"),
27        os.Getenv("DB_PASSWORD"),
28        os.Getenv("DB_HOST"),
29        os.Getenv("DB_PORT"),
30        os.Getenv("DB_NAME"),
31    )
32
33    conn, err := pgx.Connect(context.Background(), connStr)
34    if err != nil {
35        log.Fatal("Unable to connect to database:", err)
36    }
37    defer conn.Close(context.Background())
38
39    // 3. Create Gin application
40    r := gin.Default()
41
42    // 4. Register routes
43    todoRoutes := routes.TodoRoutes{DB: conn}
44    r.POST("/todos", todoRoutes.CreateTodo)
45    r.GET("/todos", todoRoutes.GetAllTodos)
46
47    // 5. Start the server
48    r.Run(":8080")
49}

3. Route Implementation (routes/todo_routes.go)
#

 1package routes
 2
 3import (
 4    "context" // Make sure to import context
 5    "github.com/gin-gonic/gin"
 6    "github.com/jackc/pgx/v4" // Make sure to import pgx
 7    "todo-api/models"
 8)
 9
10type TodoRoutes struct {
11    DB *pgx.Conn
12}
13
14func (tr *TodoRoutes) CreateTodo(c *gin.Context) {
15    var todo models.Todo
16    if err := c.ShouldBindJSON(&todo); err != nil {
17        c.JSON(400, gin.H{"error": err.Error()})
18        return
19    }
20
21    _, err := tr.DB.Exec(context.Background(), "INSERT INTO todos (title) VALUES ($1)", todo.Title)
22    if err != nil {
23        c.JSON(500, gin.H{"error": "Database operation failed"})
24        return
25    }
26
27    c.JSON(201, gin.H{"message": "Successfully created task"})
28}
29
30func (tr *TodoRoutes) GetAllTodos(c *gin.Context) {
31    rows, err := tr.DB.Query(context.Background(), "SELECT id, title FROM todos")
32    if err != nil {
33        c.JSON(500, gin.H{"error": "Query failed"})
34        return
35    }
36    defer rows.Close() // Good practice to close rows
37
38    var todos []models.Todo
39    for rows.Next() {
40        var t models.Todo
41        if err := rows.Scan(&t.ID, &t.Title); err != nil {
42            c.JSON(500, gin.H{"error": "Failed to parse results"})
43            return
44        }
45        todos = append(todos, t)
46    }
47
48    c.JSON(200, todos)
49}