A comprehensive Go backend development course project with automated commit workflows and conventional commit standards.
This project includes pre-configured git aliases for streamlined conventional commits. Run the setup script:
./scripts/git-aliases.sh
Configure git to use our commit message template:
git config commit.template .gitmessage
Install SQLC for SQL code generation:
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
Install golang-migrate for database migrations:
brew install golang-migrate
Install mockgen for generating test mocks:
go install github.com/golang/mock/mockgen@v1.6.0
Initialize SQLC configuration:
sqlc init
Note:
- SQLC generates type-safe Go code from SQL queries
- golang-migrate handles database schema migrations and versioning
- mockgen generates mock implementations for testing
- sqlc init creates a
sqlc.yaml
configuration file for code generation- All tools are essential for this project's database layer implementation
When running the API and PostgreSQL services together using Docker Compose, it's important to make sure the database is fully ready before the API service starts. If the API tries to connect before PostgreSQL is accepting connections, it will fail.
To solve this, we use a script called wait-for.sh (from eficode/wait-for v2.2.4). This script waits for a TCP host/port to become available before running the next command.
How it works in this project:
- The API service's entrypoint is set to:
entrypoint: ["/app/wait-for.sh", "postgres:5432", "--", "/app/start.sh"]
- This means:
- Wait for the
postgres
service to be ready on port 5432 - Then run
/app/start.sh
(which runs migrations and starts the app)
- Wait for the
Why is this needed?
- Docker Compose's
depends_on
only waits for the container to start, not for the database to be ready. wait-for.sh
ensures the API only starts after PostgreSQL is accepting connections, preventing race conditions and startup errors.
Where does wait-for.sh
come from?
- Sourced from: eficode/wait-for v2.2.4
- It's a widely used, open-source utility for orchestrating service startup order in Docker environments.
Related files updated:
Dockerfile
now copieswait-for.sh
and makes it executable.docker-compose.yaml
useswait-for.sh
as the entrypoint for the API service.start.sh
is used to run migrations and start the Go app after the database is ready.
Alias | Command | Example Usage |
---|---|---|
git feat |
git commit -m "feat: <message>" |
git feat "add user authentication" |
git fix |
git commit -m "fix: <message>" |
git fix "resolve database timeout" |
git docs |
git commit -m "docs: <message>" |
git docs "update API documentation" |
git refactor |
git commit -m "refactor: <message>" |
git refactor "extract validation logic" |
git test |
git commit -m "test: <message>" |
git test "add unit tests for auth" |
git chore |
git commit -m "chore: <message>" |
git chore "update dependencies" |
git style |
git commit -m "style: <message>" |
git style "fix linting issues" |
git perf |
git commit -m "perf: <message>" |
git perf "optimize database queries" |
git build |
git commit -m "build: <message>" |
git build "update Dockerfile" |
git ci |
git commit -m "ci: <message>" |
git ci "add automated testing" |
Alias | Command | Description |
---|---|---|
git ac |
git add -A && git commit |
Add all changes and commit (opens editor) |
git acp |
git add -A && git commit && git push |
Add, commit, and push |
git quick |
git add -A && git commit -m "chore: <message>" && git push |
Quick commit with chore prefix |
Alias | Command | Description |
---|---|---|
git staged |
git diff --staged |
Show staged changes |
git unstage |
git reset HEAD -- |
Unstage files |
git last |
git log -1 HEAD |
Show last commit |
# Make your code changes
# Stage specific changes (recommended)
git add -p
# Or stage all changes
git add .
# Review what's staged
git staged
# Using aliases (recommended)
git feat "add user login endpoint"
git fix "resolve null pointer in middleware"
git docs "update setup instructions"
# Or traditional way
git commit -m "feat: add user login endpoint"
# For small changes/fixes
git quick "update configuration"
# For regular workflow
git ac # Opens editor for commit message
Validate your commit messages before committing:
./scripts/validate-commit.sh "feat: add user authentication"
# Run all tests
make test
# Run tests with coverage
make coverage
This project is configured to work with the Coverage Gutters VS Code extension for visual coverage highlighting.
- Install the extension:
Coverage Gutters
by ryanluker - Generate coverage:
make coverage
- In VS Code Command Palette (
Cmd+Shift+P
):- Run:
Coverage Gutters: Display Coverage
- Run:
- π’ Green highlights: Code covered by tests
- π΄ Red highlights: Code NOT covered by tests (write tests for these!)
- π‘ Yellow highlights: Partially covered code
- π Coverage percentage in status bar
coverage.out
- Go coverage formatlcov.info
- LCOV format for VS Code extension- Run
go tool cover -html=coverage.out
for HTML coverage report
This project uses mockgen to generate mock implementations for testing. Mocks allow you to test components in isolation by replacing dependencies with controllable test doubles.
mockgen -source=db/sqlc/store.go -destination=db/mock/store.go -package=mockdb -aux_files=github.com/go-systems-lab/go-backend-masterclass/db/sqlc=db/sqlc/querier.go
-source=db/sqlc/store.go
- Source file containing the interface to mock-destination=db/mock/store.go
- Where to save the generated mock-package=mockdb
- Package name for the generated mock-aux_files=...
- Include auxiliary files for embedded interfaces
The Store
interface embeds the Querier
interface:
type Store interface {
Querier // Embedded interface
TransferTx(ctx context.Context, arg TransferTxParams) (TransferTxResult, error)
}
Without -aux_files
, mockgen can't resolve the embedded Querier
interface and fails with:
unknown embedded interface Querier
- CONTRIBUTING.md - Detailed contribution guidelines
- COMMIT_REFERENCE.md - Quick commit reference
- .gitmessage - Commit message template
- Make small, frequent commits
- Use descriptive commit messages
- Follow conventional commit format
- Commit working code
- Break features into logical commits
- Make huge commits with multiple changes
- Commit broken code
- Use vague messages like "fix stuff"
- Wait too long between commits
git feat "add user model struct"
git feat "implement user repository interface"
git feat "add user service layer"
git test "add unit tests for user service"
git docs "update API documentation for users"
If you prefer to set up aliases manually:
# Conventional commit aliases
git config alias.feat '!f() { git commit -m "feat: $1"; }; f'
git config alias.fix '!f() { git commit -m "fix: $1"; }; f'
git config alias.docs '!f() { git commit -m "docs: $1"; }; f'
# Workflow aliases
git config alias.ac '!git add -A && git commit'
git config alias.staged 'diff --staged'
git config alias.last 'log -1 HEAD'
Type | Description | Version Impact |
---|---|---|
feat |
New feature | Minor version bump |
fix |
Bug fix | Patch version bump |
docs |
Documentation changes | Patch version bump |
refactor |
Code refactoring | Patch version bump |
test |
Adding/updating tests | Patch version bump |
chore |
Maintenance tasks | Patch version bump |
perf |
Performance improvements | Patch version bump |
style |
Code style changes | Patch version bump |
build |
Build system changes | Patch version bump |
ci |
CI/CD changes | Patch version bump |
Add !
after type for breaking changes:
git feat! "remove deprecated API endpoint"
- Create ECR Repository:
simplebank
in AWS ECR - Setup IAM:
- User:
github-ci
- Group:
deployment
- Policy:
AmazonElasticContainerRegistryPublicFullAccess
- User:
- GitHub Secrets:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
-
Create RDS Instance:
- Engine: PostgreSQL 15 (Free Tier)
- DB Instance ID:
simple-bank
- Master Username:
root
- Password: Auto-generate
-
Network Configuration:
- Public Access: Yes (for development)
- Security Group:
access-postgres-anywhere
- Initial Database:
simple_bank
-
Security Group Rules:
- Edit inbound rules to allow access from anywhere (0.0.0.0/0)
-
Create Secret:
- Type: Other type of secret
- Secret Name:
simple_bank
- Key-Value Pairs:
DB_DRIVER
DB_SOURCE
SERVER_ADDRESS
TOKEN_SYMMETRIC_KEY
ACCESS_TOKEN_DURATION
-
IAM Permissions:
- Attach
SecretsManagerReadWrite
policy todeployment
group
- Attach
-
AWS CLI Setup:
# Install AWS CLI aws configure # Enter: Access Key ID, Secret Key, us-east-1, json
-
ECR Authentication & Run:
# Login to ECR aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <ecr-registry-uri> # Pull and run image docker pull <repository-uri> docker run -p 8080:8080 <image:tag> docker ps
gRPC (gRPC Remote Procedure Calls) is a modern, high-performance RPC framework that uses HTTP/2 for transport and Protocol Buffers (protobuf) for serialization. It provides:
- Type-safe APIs with auto-generated client/server code
- High performance with HTTP/2 multiplexing and binary serialization
- Cross-platform support for multiple programming languages
- Streaming support for real-time data exchange
# macOS (using Homebrew)
brew install protobuf
# Verify installation
protoc --version
# Install protobuf Go plugin
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
# Install gRPC Go plugin
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# Verify installations
protoc-gen-go --version
protoc-gen-go-grpc --version
proto/
βββ service_simple_bank.proto # Service definitions
βββ rpc_*.proto # Individual RPC definitions
pb/
βββ service_simple_bank.pb.go # Generated protobuf code
βββ service_simple_bank_grpc.pb.go # Generated gRPC server/client code
Generate Go code from proto files:
# Generate protobuf and gRPC code
protoc --proto_path=proto --go_out=pb --go_opt=paths=source_relative \
--go-grpc_out=pb --go-grpc_opt=paths=source_relative \
proto/*.proto
- Define Services: Write
.proto
files defining your gRPC services - Generate Code: Run protoc to generate Go server/client code
- Implement Server: Implement the generated service interfaces
- Create Client: Use generated client code to call services
- Test: Use tools like
grpcurl
orgrpcui
for testing
# Install grpcurl for command-line testing
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
# Install grpcui for web-based testing
go install github.com/fullstorydev/grpcui/cmd/grpcui@latest
Note: gRPC enables building scalable, type-safe APIs with excellent performance characteristics, making it ideal for microservices and high-throughput applications.
# Install Evans using Homebrew
brew tap ktr0731/evans
brew install evans
# List all available services
grpcurl -plaintext localhost:9090 list
# List methods for a specific service
grpcurl -plaintext localhost:9090 list pb.SimpleBankService
# Describe a specific method
grpcurl -plaintext localhost:9090 describe pb.SimpleBankService.CreateUser
# Call a method with data
grpcurl -plaintext -d '{
"username": "alice",
"password": "secret",
"full_name": "Alice Cooper",
"email": "alice@example.com"
}' localhost:9090 pb.SimpleBankService/CreateUser
# Start Evans with reflection
evans --host localhost --port 9090 --reflection repl
# Inside Evans:
show service # List services
package pb # Select package
service SimpleBankService # Select service
call CreateUser # Call method interactively
Note: If Evans shows no services, ensure your terminal window is large enough and server reflection is enabled (which it is by default in this project).
Install the necessary gRPC Gateway tools and plugins:
go install \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \
google.golang.org/protobuf/cmd/protoc-gen-go \
google.golang.org/grpc/cmd/protoc-gen-go-grpc
When using protoc
to generate stubs, ensure the required Google API dependencies are available to the compiler at compile time. These files can be obtained by manually cloning the googleapis repository and providing them to protoc
during code generation.
Required proto files:
google/api/annotations.proto
google/api/field_behavior.proto
google/api/http.proto
google/api/httpbody.proto
-
Clone Google APIs repository:
git clone https://github.com/googleapis/googleapis.git
-
Generate code with proper includes:
protoc --proto_path=proto \ --proto_path=googleapis \ --go_out=pb --go_opt=paths=source_relative \ --go-grpc_out=pb --go-grpc_opt=paths=source_relative \ --grpc-gateway_out=pb --grpc-gateway_opt=paths=source_relative \ proto/*.proto
Note: gRPC Gateway allows you to serve both gRPC and REST API from a single codebase by generating a reverse-proxy server that translates RESTful HTTP API into gRPC calls.
The Swagger UI assets were obtained from the dist
folder of the official swagger-ui repository.
For embedding static files (like Swagger UI assets) into the Go server binary, we use the statik
package:
# Install the statik command-line tool
go install github.com/rakyll/statik@latest
Note: Statik allows you to embed static files directly into your Go binary, eliminating the need to distribute separate static file directories with your application.