One of my self-directed exercises in learning Go: building a REST weather API that pulls data from an external provider. Weather providers typically enforce request-per-minute limits — so the challenge wasn't just "fetch the data," but "fetch it without hitting the rate limit while staying responsive."
I structured the system with layered clean architecture (domain → repository → client → service → handler) so business logic wouldn't get tangled up with HTTP client or caching details. The service layer checks Redis/Valkey first before calling the external provider — identical requests within a given time window are served straight from cache.
- Response time for previously requested data dropped significantly since no round-trip to the provider was needed
- The layered structure makes it easy to add other weather providers without touching the handler
- Became the foundation for my understanding of dependency injection & interfaces in Go
[ Client ] │ ▼ [ Handler ] │ ▼ [ Service ] ──── cache hit? ────▶ [ Redis / Valkey ] │ ▼ (cache miss) [ Repository ] ──▶ [ PostgreSQL ]