mirror of
https://github.com/Ghibranalj/ddd-sqlc.git
synced 2026-03-31 16:29:41 +07:00
No description
- Go 100%
| cmd/server | ||
| internal | ||
| .gitignore | ||
| ddd-with-sqlc.md | ||
| docker-compose.yml | ||
| go.mod | ||
| go.sum | ||
| README.md | ||
Pragmatic DDD + sqlc + Echo API Example
Clean, pragmatic architecture example with Go, sqlc, and Echo framework.
🏗️ Architecture (Pragmatic DDD)
cmd/
server/
main.go # Bootstrap: wires dependencies only
internal/
domain/ # Pure business entities
user.go # User entity + UserID type
application/ # Services (business logic orchestration)
create_user.go # CreateUserService
login.go # AuthService
infrastructure/
postgres/ # Database implementation
schema.sql
queries.sql
sqlc.yaml
user_repository.go # UserRepository (concrete type)
sqlc/ # Generated by sqlc
http/ # HTTP server implementation
server.go # Echo setup & routing
handlers.go # Request handlers
✅ Architecture Principles
| Layer | Responsibility | Dependencies |
|---|---|---|
| Domain | Business entities | None (pure Go types) |
| Application | Business logic orchestration | Domain + Infrastructure |
| Infrastructure | External concerns (DB, HTTP) | Domain + sqlc + Echo |
| main.go | Bootstrap/wiring | All layers |
Key Design Decisions:
- ✅ No repository interfaces - Concrete types for direct navigation
- ✅ No Echo in main - HTTP setup is in infrastructure layer
- ✅ Domain is pure - No sqlc, Echo, or external types
- ✅ Single Responsibility - Each layer has one clear purpose
- ✅ Navigatable - Cmd+click goes directly to implementation
Why No Interfaces?
For learning/examples with one implementation, interfaces add:
- ❌ Unnecessary indirection
- ❌ Worse IDE navigation (jumps to interface, not implementation)
- ❌ Extra boilerplate code
Pragmatic approach: Application services depend directly on concrete infrastructure types. Still clean separation, just without interface abstraction.
🚀 Quick Start
1. Start Database
docker-compose up -d
2. Run Server
go run cmd/server/main.go
# Server starts on http://localhost:8080
3. Test API
Create User:
curl -X POST http://localhost:8080/users \
-H "Content-Type: application/json" \
-d '{
"id": "user-1",
"name": "John Doe",
"email": "john@example.com",
"password": "secret123"
}'
Login:
curl -X POST http://localhost:8080/login \
-H "Content-Type: application/json" \
-d '{
"email": "john@example.com",
"password": "secret123"
}'
Response:
{
"id": "user-1",
"name": "John Doe",
"email": "john@example.com"
}
📁 Code Flow Example
Login Request Flow:
- main.go → Creates all dependencies
- Echo (infrastructure/http) → Receives HTTP request
- Handler (infrastructure/http) → Calls AuthService
- AuthService (application) → Calls UserRepository directly
- UserRepository (infrastructure/postgres) → Queries database via sqlc
- Response → Flows back up through layers
What's NOT in main.go:
- ❌ No Echo setup
- ❌ No route definitions
- ❌ No middleware configuration
- ✅ Only dependency wiring (bootstrap)
This makes the code:
- Navigable - Cmd+click goes directly to implementation
- Maintainable - Clear separation of concerns
- Simple - No unnecessary abstractions
- Clean - Each layer has single responsibility