Building Microservices with Go: Database Integration

Building Microservices with Go: Database Integration

In the previous blog, we introduced how to build a simple microservice with Go. Now, we’ll take it a step further by adding database integration, which is a crucial part of most microservice architectures. By the end of this post, you’ll learn how to connect a Go microservice to a database (PostgreSQL, in this case) using GORM, a popular ORM library for Go, perform CRUD operations, and structure your Go code to manage database logic efficiently.

Why Database Integration Matters in Microservices

Microservices often require persistent storage to manage data independently. Each microservice may have its own database to ensure loose coupling. This setup allows independent scaling, fault isolation, and decentralized data management. By using Go, which provides excellent support for database interaction through packages like database/sql, we can make our microservices both lightweight and efficient.

Choosing a Database

For this blog, we’ll integrate PostgreSQL, an open-source, powerful relational database. However, the same principles apply if you choose another database like MySQL, MongoDB, or SQLite. PostgreSQL is chosen due to its robustness and wide community support. We’ll walk through setting up GORM, connecting to a PostgreSQL database, and performing basic CRUD (Create, Read, Update, Delete) operations.

Why GORM?

GORM simplifies database interactions by allowing you to define Go structures that map to database tables. It offers features like:

  1. Automatic table creation based on Go structs.

  2. Easy migrations for schema updates.

  3. Comprehensive CRUD support with rich querying methods.

Setting Up PostgreSQL and GORM

First, we need to install PostgreSQL and GORM.

  1. Install PostgreSQL:

    • If you don’t have PostgreSQL installed, download and install it from the official website.

    • Create a new database for the microservice

        psql -U postgres
        CREATE DATABASE go_microservice_db;
      
  2. Install GORM: Add GORM and the PostgreSQL driver to your project:

     go get -u gorm.io/gorm
     go get -u gorm.io/driver/postgres
    

Database Configuration and Initialization

Let’s modify our project structure slightly to support database interactions.

  1. Create a database connection helper in the internal/ directory.

    File: internal/db/db.go

     package db
    
     import (
         "gorm.io/driver/postgres"
         "gorm.io/gorm"
         "log"
     )
    
     var DB *gorm.DB
    
     func Init() {
         dsn := "host=localhost user=postgres password=yourpassword dbname=go_microservice_db port=5432 sslmode=disable"
         var err error
         DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
         if err != nil {
             log.Fatal("Failed to connect to database:", err)
         }
         log.Println("Database connected")
     }
    

    This code initializes the connection to the PostgreSQL database using GORM. Replace yourpassword with your PostgreSQL password.

  2. Create a model that represents the data we will store in the database.

    File: internal/models/user.go

     package models
    
     import "gorm.io/gorm"
    
     type User struct {
         gorm.Model
         Name  string `json:"name"`
         Email string `json:"email"`
     }
    

    This struct defines a User model with fields for Name and Email. GORM will automatically map this struct to a users table in PostgreSQL.

    CRUD Operations

    Now that we have a database connection and model, let’s write the microservice to handle CRUD operations.

    1. Migrate the schema: GORM can automatically create the users table for us. Call the AutoMigrate function when the service starts.

      File: cmd/service1/main.go

       package main
      
       import (
           "go-microservice/internal/db"
           "go-microservice/internal/models"
           "log"
           "net/http"
           "gorm.io/gorm"
           "encoding/json"
           "io/ioutil"
       )
      
       func createUserHandler(w http.ResponseWriter, r *http.Request) {
           body, _ := ioutil.ReadAll(r.Body)
           var user models.User
           json.Unmarshal(body, &user)
      
           db.DB.Create(&user)
           w.WriteHeader(http.StatusCreated)
           json.NewEncoder(w).Encode(user)
       }
      
       func listUsersHandler(w http.ResponseWriter, r *http.Request) {
           var users []models.User
           db.DB.Find(&users)
           w.Header().Set("Content-Type", "application/json")
           json.NewEncoder(w).Encode(users)
       }
      
       func main() {
           db.Init()
      
           // Migrate the schema
           db.DB.AutoMigrate(&models.User{})
      
           http.HandleFunc("/users", createUserHandler)
           http.HandleFunc("/users/list", listUsersHandler)
      
           log.Println("Server running on port 8080")
           http.ListenAndServe(":8080", nil)
       }
      
    2. Running the service: When you run the service, it will connect to PostgreSQL, create the users table, and expose two routes:

      • POST /users: to create a new user by sending a JSON payload like { "name": "John Doe", "email": "john@example.com" }.

      • GET /users/list: to fetch a list of all users.

    3. Testing the CRUD endpoints:

      • Use curl to test the endpoints:

          # Create a new user
          curl -X POST -d '{"name":"John Doe", "email":"john@example.com"}' -H "Content-Type: application/json" http://localhost:8080/users
        
          # Fetch all users
          curl http://localhost:8080/users/list
        

Conclusion

In this blog post, we integrated PostgreSQL into our Go microservice using GORM. We demonstrated how to:

  • Set up a PostgreSQL database.

  • Create a database connection with GORM.

  • Define a model and perform basic CRUD operations.

In the next post, we’ll explore inter-service communication using HTTP and gRPC, diving deeper into how microservices can communicate with each other.