A TypeScript weather forecast service using the National Weather Service API, built with clean hexagonal architecture principles.
- Get today's weather forecast for any US location
- Temperature classification (hot/cold/moderate)
- Input validation with Zod
- Caching with TTL
- Retry logic for external API calls
- Structured logging with Winston
- Comprehensive error handling
The project follows Hexagonal Architecture (Ports & Adapters pattern) with clear separation:
- Domain: Business logic, entities, value objects
- Application: Use cases and port interfaces
- Adapters: HTTP controllers, external API clients, cache
- Infrastructure: Configuration, logging, DI container
- TypeScript 5.3
- Express 4.18
- Zod 3.22 (validation)
- TSyringe 4.8 (dependency injection)
- Axios 1.6 with axios-retry
- Winston 3.11 (logging)
- Jest 29.7 (testing)
- Node.js >= 18.0.0
- npm >= 9.0.0
npm installThe project uses environment-specific configuration files located in the env/ folder:
env/.env.development- Used in development mode (default)env/.env.production- Used in productionenv/.env.test- Used for testing
The app automatically loads the correct file based on NODE_ENV. You can create env/.env.local to override any values locally (this file is gitignored).
Development mode:
npm run devProduction:
npm run build
npm startnpm test
npm run test:coverageGET /api/weather/forecast?latitude={lat}&longitude={lon}
Example:
curl "http://localhost:3000/api/weather/forecast?latitude=40.7128&longitude=-74.0060"Response:
{
"location": {
"latitude": 40.7128,
"longitude": -74.006
},
"forecast": "Partly Cloudy",
"temperature": "75.0°F",
"temperatureType": "moderate",
"retrievedAt": "2025-12-01T10:30:00.000Z"
}GET /api/health
- Hot: >= 80°F (27°C)
- Moderate: 50-79°F (10-26°C)
- Cold: < 50°F (10°C)
The API returns appropriate HTTP status codes:
200- Success400- Invalid coordinates404- Weather data not found422- Validation error500- Internal server error502- External API error503- Service unavailable
src/
├── domain/ # Business logic
│ ├── entities/
│ ├── value-objects/
│ ├── services/
│ └── exceptions/
├── application/ # Use cases
│ ├── ports/
│ └── usecases/
├── adapters/ # External interfaces
│ ├── inbound/http/
│ └── outbound/
├── infrastructure/ # Cross-cutting
│ ├── config/
│ ├── di/
│ ├── logging/
│ └── server/
└── index.ts
- Clean separation of concerns
- Easily testable in isolation
- Framework-independent business logic
- Flexible adapter implementations
- Industry-standard DI container
- Type-safe dependency injection
- Minimal boilerplate
- Good TypeScript support
In-memory cache with 30-minute TTL reduces API calls significantly. For production with multiple instances, consider Redis.
3 retry attempts with exponential backoff (1s, 2s, 4s) for network failures and 5xx errors.
- The National Weather Service API only covers US locations
- Coordinates are validated and rounded to 4 decimal places
- All dependencies use exact versions (no semver ranges)
- nodemon is correctly placed in devDependencies
MIT