๐Ÿ—๏ธ Subscription Tracker API Architecture

Layered architecture with dependency inversion principle

๐ŸŒ PRESENTATION LAYER (Presentation Layer) High Level
๐ŸŽฏ HTTP Handlers
๐Ÿ“ Request/Response Models
โœ… Validation
๐Ÿ”’ CORS Middleware
๐Ÿ“Š Swagger Documentation
handlers.NewSubscriptionHandler(service SubscriptionServiceInterface, logger)

Responsibility: HTTP requests/responses, input data validation, status codes

Depends on: SubscriptionServiceInterface

โฌ‡๏ธ
๐Ÿง  BUSINESS LAYER (Business Logic) Middle Level
โšก Subscription Service
๐Ÿ”„ Transaction Execution
๐Ÿ“‹ Business Rules
๐Ÿ’ฐ Cost Calculation
๐Ÿ›ก๏ธ Data Validation
service.NewSubscriptionService(repo SubscriptionRepositoryInterface, logger)

Responsibility: Business rules, data validation, transaction execution

Depends on: SubscriptionRepositoryInterface

โฌ‡๏ธ
๐Ÿ—„๏ธ DATA LAYER (Data Layer) Low Level
๐Ÿ“ฆ Subscription Repository
๐Ÿ” CRUD Operations
๐Ÿ“ˆ Query Optimization
repository.NewSubscriptionRepository(db *gorm.DB, logger)

Responsibility: Database operations, working with GORM

Depends on: *gorm.DB (concrete implementation)

โฌ‡๏ธ
๐Ÿ”Œ EXTERNAL LAYER (External Services) Infrastructure
๐Ÿ˜ PostgreSQL Database
๐Ÿ“ Logrus Logger
๐Ÿ”„ Transaction Management
โš™๏ธ Configuration
๐Ÿ”„ Database Migrations

Responsibility: External dependencies, database, file system, network

๐Ÿ”„ Dependency Inversion Principle in Action

Handler
(high level)
ServiceInterface
(abstraction)
Service
(middle level)
RepositoryInterface
(abstraction)
Repository
(low level)

โœ… What we get:

  • ๐Ÿงช Testability: We can easily mock dependencies
  • ๐Ÿ”ง Flexibility: We can change implementations without code changes
  • ๐Ÿ”— Loose coupling: Layers don't know about concrete implementations
  • ๐Ÿ“ฆ Modularity: Each layer has clear responsibility

๐Ÿ”„ Request Execution Flow

1. Handler
Receives HTTP request
โ†’
2. Service
Executes business logic
โ†’
3. Repository
Works with database
โ†’
4. Database
Returns data

Each layer only knows about its immediate dependencies through interfaces