Introduction: Why Go is the Ideal Language for Microservices?
\n\nMicroservice architecture has become the de facto standard for building modern scalable applications. The Go language (Golang), created within Google, is ideally suited for this task due to its simplicity, performance, and built-in concurrency support. In this article, we will break down the complete cycle of creating a microservice in Go: from architecture design to production deployment.
\n\nGo offers fast compilation, minimal memory consumption, and native work with goroutines — lightweight threads. This makes it an excellent choice for high-load distributed systems. We will cover key concepts, write code examples, and discuss best practices.
\n\n1. Designing a Microservice Architecture in Go
\n\n1.1. Principles of Microservice Architecture
\n\nBefore writing code, it is necessary to define the boundaries of microservices. Key principles:
\n\n- \n
- Single Responsibility — each service is responsible for one business function. \n
- Independent Deployment — each microservice can be updated without stopping the entire system. \n
- Loose Coupling — services communicate through clearly defined APIs. \n
- Decentralized Data Management — each service has its own database. \n
1.2. Go Project Structure for a Microservice
\n\nRecommended folder structure for a microservice in Go:
\n\nmy-service/\n├── cmd/\n│ └── server/\n│ └── main.go # Entry point\n├── internal/\n│ ├── handler/ # HTTP/gRPC handlers\n│ ├── service/ # Business logic\n│ ├── repository/ # Database operations\n│ └── model/ # Data structures\n├── pkg/\n│ └── api/ # Common proto files (gRPC)\n├── config/\n│ └── config.go # Configuration\n├── migrations/ # Database migrations\n├── Dockerfile\n└── go.mod\n\n1.3. Example of a Simple Microservice
\n\nLet's create a basic HTTP microservice for user management. We'll start by defining the model and repository:
\n\n// internal/model/user.go\npackage model\n\ntype User struct {\n ID int64 `json:"id"`\n Name string `json:"name"`\n Email string `json:"email"`\n}\n\n// internal/repository/user_repo.go\npackage repository\n\nimport (\n "context"\n "my-service/internal/model"\n)\n\ntype UserRepository interface {\n GetByID(ctx context.Context, id int64) (*model.User, error)\n Create(ctx context.Context, user *model.User) (int64, error)\n}\n\ntype inMemoryRepo struct {\n users map[int64]*model.User\n nextID int64\n}\n\nfunc NewInMemoryRepo() UserRepository {\n return &inMemoryRepo{\n users: make(map[int64]*model.User),\n nextID: 1,\n }\n}\n\nfunc (r *inMemoryRepo) GetByID(ctx context.Context, id int64) (*model.User, error) {\n user, ok := r.users[id]\n if !ok {\n return nil, fmt.Errorf("user not found")\n }\n return user, nil\n}\n\nfunc (r *inMemoryRepo) Create(ctx context.Context, user *model.User) (int64, error) {\n user.ID = r.nextID\n r.users[user.ID] = user\n r.nextID++\n return user.ID, nil\n}\n\n2. Communication Between Microservices: REST, gRPC, and Queues
\n\n2.1. REST API in Go
\n\nFor synchronous interaction, REST or gRPC is most often used. Let's look at a REST controller using the standard net/http library and the chi router:
// internal/handler/user_handler.go\npackage handler\n\nimport (\n "encoding/json"\n "net/http"\n "strconv"\n "my-service/internal/service"\n "github.com/go-chi/chi/v5"\n)\n\ntype UserHandler struct {\n svc *service.UserService\n}\n\nfunc NewUserHandler(svc *service.UserService) *UserHandler {\n