Spring Boot-based microservice to retrieve airport information using ICAO codes from AviationAPI.com.
🚀 Quick Start: Want to start immediately? See QUICK_START.md for a 5-minute guide!
This project is a production-ready microservice implementation that provides a REST API to query airport information based on 4-character ICAO codes. It is built with a focus on scalability, resilience, and observability.
- ✅ REST API endpoint for airport lookup by ICAO code
- ✅ Integration with public aviation API (aviationapi.com)
- ✅ Clean Architecture with 4 distinct layers
- ✅ Command-Executor Pattern for extensibility
- ✅ Comprehensive resilience patterns (Circuit Breaker, Retry, Rate Limiter, Timeout)
- ✅ High-performance caching with Caffeine
- ✅ Full observability (Logging, Metrics, Health Checks, Tracing)
- ✅ Reactive non-blocking architecture with WebFlux
- ✅ OpenAPI/Swagger documentation
- ✅ Comprehensive test coverage
- Java 21 or higher
- Maven 3.9+ for build management
- Internet connectivity for accessing aviationapi.com
git clone <repository-url>
cd aviation-api-wrappermvn clean installThe build will:
- Compile all source code
- Run all unit & integration tests
- Package the application into an executable JAR
Expected output:
[INFO] BUILD SUCCESS
[INFO] Total time: XX.XXX s
Option A: Using Maven
mvn spring-boot:runOption B: Using Java JAR
java -jar target/aviation-api-0.0.1-SNAPSHOT.jarOption C: Using Docker
# Build image
docker build -t aviation-api:latest .
# Run container
docker run -p 8080:8080 --name aviation-api aviation-api:latestOption D: Using Docker Compose (with monitoring)
# Start all services (API + Prometheus + Grafana)
docker-compose up -d
# View logs
docker-compose logs -f aviation-api
# Stop all services
docker-compose downRunning services:
- Aviation API: http://localhost:8080
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000 (admin/admin)
The application will start at http://localhost:8080
mvn testmvn test -Dtest=AirportControllerIntegrationTestThis project has 3 levels of testing:
-
Unit Tests -
GetAirportByIcaoCommandHandlerTest- Tests command handler in isolation
- Mocks dependencies
-
Integration Tests -
AviationApiClientTest- Tests WebClient using MockWebServer
- Verifies resilience patterns
-
End-to-End Tests -
AirportControllerIntegrationTest- Full Spring Boot context
- Tests complete request flow
- Validates HTTP responses
GET /api/v1/airports/{icao}Path Parameters:
icao(required): 4-character ICAO code (e.g., KJFK, EGLL, YSSY)
Example Request:
curl http://localhost:8080/api/v1/airports/KJFKSuccess Response (200 OK):
{
"icaoCode": "KJFK",
"iataCode": "JFK",
"name": "John F Kennedy International Airport",
"city": "New York",
"country": "United States",
"coordinates": {
"latitude": 40.6398,
"longitude": -73.7789
},
"timezone": "America/New_York",
"elevationFeet": 13
}Error Responses:
400 Bad Request- Invalid ICAO code format404 Not Found- Airport not found429 Too Many Requests- Rate limit exceeded503 Service Unavailable- Circuit breaker open (upstream API down)
curl http://localhost:8080/actuator/healthcurl http://localhost:8080/actuator/metrics
curl http://localhost:8080/actuator/prometheusOpen browser to: http://localhost:8080/swagger-ui.html
This project implements Clean Architecture with 4 isolated layers:
┌─────────────────────────────────────────────┐
│ Presentation Layer │
│ (Controllers, Exception Handlers, DTOs) │
└────────────────┬────────────────────────────┘
│
┌────────────────▼────────────────────────────┐
│ Application Layer │
│ (Commands, Handlers, Executor, Use Cases) │
└────────────────┬────────────────────────────┘
│
┌────────────────▼────────────────────────────┐
│ Domain Layer │
│ (Entities, Ports, Business Logic) │
└─────────────────────────────────────────────┘
▲
┌────────────────┴────────────────────────────┐
│ Infrastructure Layer │
│ (API Clients, Config, External Systems) │
└─────────────────────────────────────────────┘
Benefits:
- Testability: Business logic can be tested without external dependencies
- Maintainability: Changes in one layer do not affect others
- Provider Independence: Easy to swap aviation data providers
- Clear Boundaries: Each layer has a single responsibility
Implementation uses the Command-Executor Pattern for request handling:
- Command: Immutable data object representing an intent
- CommandHandler: Executes business logic for a specific command
- CommandExecutor: Router that dispatches commands to the appropriate handler
Benefits:
- Extensibility: Add new feature = create new command (Open/Closed Principle)
- Single Responsibility: Each handler focuses on one use case
- Auditability: Easy to add logging/metrics around command execution
- Testability: Commands and handlers can be tested independently
| Technology | Purpose | Rationale |
|---|---|---|
| Spring WebFlux | Reactive web framework | Non-blocking I/O for high throughput |
| Resilience4j | Resilience patterns | Modern library with Spring integration |
| Caffeine | Caching | High-performance in-memory cache |
| Micrometer | Metrics & Tracing | Industry standard observability |
| Springdoc OpenAPI | API Documentation | Auto-generate OpenAPI spec |
| Lombok | Boilerplate reduction | Clean, maintainable code |
The application implements multiple layers of resilience:
Configuration:
- Sliding window: 10 calls
- Failure threshold: 50%
- Wait duration: 30 seconds
- Half-open calls: 3Purpose: Prevents cascading failures when upstream API is down
- Open state: Immediately reject request without calling API
- Half-open state: Test if API has recovered
- Closed state: Normal operation
Configuration:
- Max attempts: 3
- Backoff: Exponential (500ms → 1s → 2s)
- Retry on: 500, 503, 504 errors
- Don't retry: 400, 404 errorsPurpose: Handles transient failures (network glitches, temporary unavailability)
Configuration:
- Limit: 100 requests per minute
- Timeout: 5 seconds to acquire permissionPurpose: Protects upstream API from overload, complies with rate limits
Configuration:
- Request timeout: 3 seconds
- Overall timeout: 10 secondsPurpose: Prevents indefinite waiting, frees up resources quickly
Configuration:
- Max size: 1000 entries
- TTL: 60 minutes
- Eviction: LRU (Least Recently Used)Purpose: Reduces load on upstream API, improves response time
All errors are returned in a consistent format:
{
"error": "Error Type",
"message": "Detailed error message",
"timestamp": "2025-11-30T10:30:00Z",
"path": "/api/v1/airports/INVALID"
}| Scenario | Handling Strategy |
|---|---|
| Upstream API down | Circuit breaker opens → 503 response |
| Transient network error | Retry with exponential backoff |
| Invalid ICAO code | Immediate 400 response (no retry) |
| Airport not found | 404 response (no retry) |
| Timeout | Cancel request after 3s → retry or fail |
| Rate limit hit | Queue request or 429 response |
- Structured logging with SLF4J
- Trace context included (traceId, spanId)
- Log levels: INFO (default), DEBUG (for troubleshooting)
Sample log:
2025-11-30 10:30:15.123 [http-nio-8080-exec-1] INFO [a1b2c3,d4e5f6] AirportController - Received request for airport with ICAO: KJFK
Exposed via Prometheus format at /actuator/prometheus:
- Request count & duration
- Circuit breaker state
- Cache hit/miss ratio
- JVM metrics (memory, threads, GC)
GET /actuator/healthReturns:
- Application status (UP/DOWN)
- Disk space
- Circuit breaker status
- W3C Trace Context propagation
- Brave tracer implementation
- Ready to export to Zipkin/Jaeger
Key configuration properties in application.yml:
# Server
server.port: 8080
# Aviation API
aviation.api.base-url: https://api.aviationapi.com
aviation.api.timeout-seconds: 3
aviation.api.max-retries: 3
# Cache
spring.cache.caffeine.spec: maximumSize=1000,expireAfterWrite=60m
# Resilience4j
resilience4j.circuitbreaker.instances.aviationApi:
failureRateThreshold: 50
waitDurationInOpenState: 30sTo custom configuration, override via:
- Environment variables
- External
application.yml - Command line arguments:
--server.port=9090
Below are the parts assisted by AI tools and have been reviewed/validated:
- Boilerplate configuration classes (
WebClientConfiguration,CacheConfiguration) - OpenAPI configuration setup
- Test scaffolding and mock data setup
- Initial project structure with Maven dependencies
- Architecture decisions (Clean Architecture + Command Pattern)
- Resilience patterns implementation
- Business logic in command handlers
- Error handling strategies
- Domain model design
- Core business logic
- Command validation logic
- Integration with aviation API
- Test scenarios and assertions
- Documentation and README
Note: All code has been understood, tested, and validated for production readiness.
aviation-api-wrapper/
├── src/
│ ├── main/
│ │ ├── java/com/github/b3kt/aviation/
│ │ │ ├── domain/ # Core business logic
│ │ │ │ ├── model/ # Domain entities
│ │ │ │ ├── port/ # Port interfaces
│ │ │ │ └── exception/ # Domain exceptions
│ │ │ ├── application/ # Use cases
│ │ │ │ ├── command/ # Commands & handlers
│ │ │ │ ├── executor/ # Command executor
│ │ │ │ └── dto/ # Application DTOs
│ │ │ ├── infrastructure/ # External integrations
│ │ │ │ ├── client/ # API clients
│ │ │ │ └── config/ # Spring configurations
│ │ │ └── presentation/ # API layer
│ │ │ ├── controller/ # REST controllers
│ │ │ └── exception/ # Exception handlers
│ │ └── resources/
│ │ └── application.yml # Configuration
│ └── test/ # Test classes
├── pom.xml # Maven dependencies
├── README.md # This file
└── assignment.md # Original requirements
- Accept HTTP requests to fetch airport by ICAO
- Query aviation API (https://aviationapi.com)
- Clean response format with key airport info
- Handle upstream failures gracefully
- Clean service layering (4 layers)
- Stateless design
- Ready for horizontal scaling
- Efficient caching
- Retry logic with exponential backoff
- Circuit breaker implementation
- Fallback strategies
- Timeout handling
- Rate limiting
- Not tightly coupled to provider
- Port/Adapter pattern
- Command pattern for new features
- Structured logging
- Error transparency
- Metrics readiness (Prometheus)
- Health checks
- Executable Maven project
- Complete README with instructions
- Integration tests
- Architecture documentation
- Error handling notes
- AI disclosure
mvn spring-boot:run -Dspring-boot.run.profiles=devmvn spring-boot:run -Dlogging.level.com.github.b3kt.aviation=DEBUGmvn clean test jacoco:report
# Report: target/site/jacoco/index.htmlFor questions or issues:
- Check assignment.md for requirements
- Review walkthrough.md for implementation details
- Check console logs for troubleshooting
Notes:
- assignment.md is a scope for ai assisted development
- walkthrough.md is an initial boilerplate implementation plan generated using Claude Sonnet 4.5
Built with ❤️ using Clean Architecture principles