Microservices have become the de facto standard for building scalable, maintainable, and robust backend systems. Go (Golang), with its simplicity, performance, and strong concurrency support, is an excellent choice for developing microservices. In this guide, we'll walk through building a microservice using a ready-to-use Go microservice template.
Why Go for Microservices?
- Performance: Go compiles to native code and offers great runtime efficiency.
- Simplicity: The language is easy to learn and encourages clean, readable code.
- Concurrency: Goroutines and channels make concurrent programming straightforward.
- Strong Standard Library: Go's standard library covers most needs for microservice development.
Project Structure Overview
A well-structured project is crucial for maintainability. Here’s a typical layout:
go-microservice-template/
├── cmd/
│ └── main.go # Entry point
├── internal/
│ ├── api/
│ │ └── rest/
│ │ ├── rest.go # REST server setup
│ │ ├── handler/
│ │ │ └── handler.go # HTTP handlers
│ │ └── router/
│ │ └── router.go # Route definitions
│ ├── app/
│ │ └── app.go # App lifecycle
│ ├── repository/
│ │ └── repository.go # Data access
│ └── service/
│ └── service.go # Business logic
├── pkg/
│ ├── models.go # Shared models
│ └── response.go # Response helpers
├── scripts/ # Utility scripts
├── Makefile # Makefile for build automation
├── go.mod
├── go.sum
├── LICENSE
└── README.md
Why This Structure Supports Scalable Microservices
A well-organized project structure is essential for building scalable and maintainable microservices. This template follows Go community best practices and separates concerns clearly, making it easy to extend, test, and manage as your service grows.
Folder-by-Folder Breakdown
- cmd/: Contains the entry point(s) for your application. Each executable should have its own subfolder, making it easy to add CLI tools or multiple services in the future.
-
internal/: Holds all application-specific code. The
internal
directory restricts import access, ensuring that code here cannot be imported from outside the project, which enforces encapsulation and prevents accidental dependencies.- api/rest/: Contains REST server setup, handlers, and routers. This keeps your API layer modular and easy to update as endpoints grow.
- app/: Manages application lifecycle and startup logic, centralizing configuration and initialization.
- repository/: Handles data access, making it easy to swap databases or external services without affecting business logic.
- service/: Contains business logic, keeping your core functionality decoupled from transport and storage layers.
- pkg/: For code that can be shared across projects or is intended for public use. This is ideal for reusable models, helpers, and utilities.
- scripts/: Stores automation and setup scripts, helping with DevOps, CI/CD, and local development tasks.
This separation of concerns allows teams to work independently on different parts of the service, supports testing and code reuse, and makes it straightforward to scale the codebase as requirements evolve. By following this structure, you ensure your microservice remains robust, modular, and ready for future growth.
Libraries Used
This template leverages several key Go libraries from the oss.nandlabs.io/golly
suite to streamline development and testing:
- oss.nandlabs.io/golly/rest: Provides REST server utilities and interfaces for building HTTP APIs.
- oss.nandlabs.io/golly/lifecycle: Manages application lifecycle, including startup and graceful shutdown of components.
- oss.nandlabs.io/golly/assertion: Used for expressive assertions in unit tests, making test code more readable and robust.
You can add more libraries as needed for your business logic, database access, or API integrations. All dependencies are managed via Go modules (go.mod
).
Step 1: Clone the Template
Start by cloning the template repository:
git clone https://github.com/neo7337/go-microservice-template.git
cd go-microservice-template
Step 2: Update the Module Name
Edit go.mod
to use your own module path:
module github.com/yourusername/your-microservice
Then tidy up dependencies:
go mod tidy
Step 3: Define Your Data Models
Add or modify structs in pkg/models.go
to represent your domain entities. For example:
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email"`
}
Step 4: Implement Business Logic
Write your core business logic in the internal/service/
package. This keeps your code modular and testable.
Step 5: Set Up Data Access
Implement repository functions in internal/repository/
to interact with databases or external APIs.
Step 6: Create API Handlers and Routes
- Add handler functions in
internal/api/rest/handler/
for each endpoint. - Register routes in
internal/api/rest/router/router.go
and link them to handlers.
Example: Adding a Concurrency Endpoint
To demonstrate Go's concurrency, the template includes a /api/concurrency-demo
endpoint. This endpoint launches two goroutines in parallel—one fetching users, another simulating an external call—and aggregates their results:
func ConcurrencyDemoHandler(ctx rest.ServerContext) {
type result struct {
Source string `json:"source"`
Data interface{} `json:"data"`
}
results := make(chan result, 2)
go func() {
users, _ := service.GetUsers()
results <- result{Source: "users", Data: users}
}()
go func() {
info := map[string]string{"message": "Hello from goroutine!"}
results <- result{Source: "info", Data: info}
}()
resp := make(map[string]interface{})
for i := 0; i < 2; i++ {
r := <-results
resp[r.Source] = r.Data
}
pkg.ResponseJSON(ctx, 200, resp)
}
Sample response:
{
"users": [
{"id":1,"name":"John Doe","age":30,"email":"john.doe@mail.com"},
{"id":2,"name":"Jane Smith","age":25,"email":"jane.smith@mail.com"}
],
"info": {"message": "Hello from goroutine!"}
}
Step 7: Customize Application Startup
Modify internal/app/app.go
to register additional components or change startup behavior as needed.
Step 8: Run Your Microservice
Start your service locally:
go run cmd/main.go
By default, your API will be available at http://localhost:8282/api
.
Step 9: Extend and Organize
- Add more packages under
internal/
as your service grows. - Use the
pkg/
directory for shared utilities and types. - Add scripts to the
scripts/
directory for automation or setup tasks.
Step 10: Testing
The template includes example test cases for both the repository and response utility layers:
-
internal/repository/repository_test.go
tests theGetUsers
function, ensuring correct user data is returned. -
pkg/response_test.go
tests theResponseJSON
utility, verifying status code, headers, and JSON output.
Add your own tests alongside your code or in a dedicated test/
directory. To run all tests:
go test ./...
Repository
You can find the template repository here: neo7337/go-microservice-template
Conclusion
With this template and step-by-step approach, you can quickly scaffold, develop, and scale robust Go microservices. The clear separation of concerns and modular structure make it easy to maintain and extend your services as your needs evolve.
Ready to build your next microservice? Fork the template and start coding!
Top comments (0)