- 📋 API Versioning Strategy with V1.0 implementation and V2.0 roadmap ready
- 🐘 PostgreSQL persistence with JPA
- 🔄 Flyway database migrations
- 📚 Swagger/OpenAPI documentation with microservice examples
- 💊 Health checks with microservice connectivity monitoring
- 🔗 Connectivity endpoints for verifying com## 🧪 Testing and Code Quality
- ✅ 47 tests implemented distributed across all layers:
- 🔬 30 Unit Tests: Domain, Application, and Infrastructure
- 🔗 17 Integration Tests: End-to-end with TestContainers
- 🎯 88% instruction coverage (1,204/1,367 instructions)
Layer | Coverage | Status |
---|---|---|
Infrastructure layer | 100% | ✅ Complete |
Application UseCase | 96% | ✅ Excellent |
Domain Model | 95% | ✅ Excellent |
Application DTO | 82% | ✅ Good |
Domain Service | 42% | |
Main Application Class | 37% |
# Run all tests
mvn clean test
# Run tests with coverage report
mvn clean test jacoco:report
# View coverage report
open target/site/jacoco/index.html
- Domain Model Tests: Entity and domain logic validation
- UseCase Tests: Use case testing with mocks
- DTO Tests: Data transformation validation
- Infrastructure Tests: Adapter testing
- API Tests: End-to-end REST endpoint testing
- Database Tests: PostgreSQL integration using TestContainers
- Security Tests: Authentication and authorization validation
- Health Check Tests: Health endpoint verification
# 1. Verify all services are running
docker-compose ps
# 2. Test application health check
curl http://localhost:8080/actuator/health
# 3. Test main endpoint with API Key
curl -H "X-API-Key: dev_api_key_for_local_development_12345" \
http://localhost:8080/api/v1/products
# 4. Verify microservice connectivity
curl -H "X-API-Key: dev_api_key_for_local_development_12345" \
http://localhost:8080/api/connectivity/status
curl -H "X-API-Key: dev_api_key_for_local_development_12345" \
-H "Accept: application/vnd.api+json" \
http://localhost:8080/api/v1/products
curl -H "X-API-Key: dev_api_key_for_local_development_12345" \
-H "Accept: application/vnd.api+json" \
http://localhost:8080/api/v1/products/1
curl -X POST \
-H "X-API-Key: dev_api_key_for_local_development_12345" \
-H "Content-Type: application/vnd.api+json" \
-d '{
"data": {
"type": "products",
"attributes": {
"name": "New Product",
"price": 199.99
}
}
}' \
http://localhost:8080/api/v1/products
curl -X PUT \
-H "X-API-Key: dev_api_key_for_local_development_12345" \
-H "Content-Type: application/vnd.api+json" \
-d '{
"data": {
"type": "products",
"id": "1",
"attributes": {
"name": "Updated Product",
"price": 299.99
}
}
}' \
http://localhost:8080/api/v1/products/1
- Open http://localhost:3000
- Login:
admin
/admin123
- Go to Dashboards → Java Product API Logs
- View application metrics
# View application logs
docker-compose logs -f java-product-api
# View specific query logs
docker-compose logs java-product-api | grep "GET /api/v1/products"
*For detailed testing information, see Developer Guide*her microservices
- 📝 Structured JSON logging for Loki/Grafanatation](http://localhost:8080/swagger-ui/index.html)** - Interactive Swagger UI (when running)
- 🏥 Health Check - Application health status
- 🔗 Connectivity Status - Microservice connectivity monitoringct API
A REST API developed with Spring Boot 3 for product management, designed as part of a microservices architecture. Implements modern design patterns, complete observability, and is production-ready.
This API is part of a backend technical assessment that demonstrates:
- Hexagonal Architecture with clear separation of concerns
- RESTful APIs following JSON:API and OpenAPI standards
- Security through API Key authentication
- Complete observability with Loki, Grafana, and Promtail
- Containerization with Docker and Docker Compose
- Robust testing with 88% coverage (47 tests implemented)
- Comprehensive technical documentation and integration guides
- Spring Boot 3.2.0 with Java 17
- Spring Data JPA for persistence
- Spring Security for authentication
- Flyway for database migrations
- Hexagonal Architecture (Domain, Application, Infrastructure)
- Domain-Driven Design with domain entities and services
- Dependency Injection and SOLID principles
- API Versioning with URI Path strategy
- Structured Logging with JSON format for Loki
- Custom Health Checks for microservices
- Grafana Dashboards for real-time monitoring
- Connectivity Endpoints to verify service status
- 88% code coverage (target: 90%)
- 47 tests implemented: 30 unit + 17 integration tests
- TestContainers for PostgreSQL integration testing
- JaCoCo for coverage reports
Document | Description |
---|---|
🚀 Developer Guide | Complete development and setup guide |
🔗 Microservice Integration | Integration guide for microservices |
💡 Integration Examples | Practical API usage examples |
📊 Observability Guide | Loki + Grafana setup and usage |
📖 API Versioning Guide | API versioning strategy |
📝 Microservice Status | Current architecture status |
- 📖 API Documentation - Interactive Swagger UI
- 🏥 Health Check - Application status
- 🔗 Connectivity Status - Microservices monitoring
- 📊 Grafana Dashboard - Observability dashboards
- JSON:API compliant endpoints for external integrations
- Simple JSON endpoints optimized for microservice communication
- API Versioning with stable V1.0 and V2.0 roadmap
- Robust validation of input data
- API Key Authentication via
X-API-Key
header - CORS configured for development and production
- Input validation with Bean Validation
- Security headers configured
- PostgreSQL as primary database
- JPA/Hibernate for ORM
- Flyway for database version control
- Optimized connection pooling
- Structured JSON logging for Loki aggregation
- Custom metrics for Grafana dashboards
- Custom health indicators
- Distributed tracing ready
- 🚀 Developer Guide - Complete setup, testing, and development guide
- 🔗 Microservice Integration - Simple guide for consuming APIs
- 💡 Integration Examples - Practical examples for inventory microservice
- � Observability Guide - Loki + Grafana dashboard usage and monitoring
- �📖 API Documentation - Interactive Swagger UI (when running)
- 🏥 Health Check - Application health status
- Spring Boot 3 with Java 17
- Hexagonal Architecture (Domain, Application, Infrastructure layers)
- 🎯 Dual API Design:
- JSON:API endpoints for external integrations (
/api/products
) - Simple JSON endpoints for microservice communication (
/api/internal/products
)
- JSON:API endpoints for external integrations (
- 🔐 API Key security via X-API-Key header
- 🐘 PostgreSQL persistence with JPA
- 🔄 Flyway database migrations
- 📚 Swagger/OpenAPI documentation with microservice examples
- 💊 Health checks with microservice connectivity monitoring
- � Connectivity endpoints for verifying communication with other microservices
- �📝 Structured JSON logging for Loki/Grafana
- 🧪 Unit & Integration tests with JUnit and Testcontainers
- 🐳 Docker support with multi-environment configurations
The application implements Hexagonal Architecture to keep the domain independent of external frameworks and technologies:
src/main/java/com/cristianino/productapi/
├── 🎯 domain/ # BUSINESS CORE
│ ├── model/ # Domain entities (Product)
│ ├── port/ # Interfaces (ProductRepository)
│ └── service/ # Pure business logic
├── 🔄 application/ # USE CASES
│ ├── dto/ # DTOs and JSON:API structures
│ └── usecase/ # Application services (ProductUseCase)
└── 🔧 infrastructure/ # EXTERNAL ADAPTERS
├── config/ # Configurations (Security, OpenAPI)
├── persistence/ # JPA adapters (ProductEntity, Repository)
├── service/ # Infrastructure services
├── util/ # Utilities and helpers
└── web/ # REST controllers
- 🎯 Domain-Driven Design: Domain is completely isolated
- 🔄 Dependency Inversion: Dependencies point towards the domain
- 🔧 Single Responsibility: Each layer has a specific responsibility
- 📦 Clean Code: Readable, maintainable, and testable code
Pattern | Location | Purpose |
---|---|---|
Repository | domain/port/ |
Persistence abstraction |
Use Case | application/usecase/ |
Business logic orchestration |
DTO | application/dto/ |
Data transfer |
Entity | domain/model/ |
Domain modeling |
Adapter | infrastructure/ |
Port implementations |
- Spring Boot 3.2.0 - Main framework
- Spring Data JPA - Persistence and ORM
- Spring Security - Authentication and authorization
- Spring Web - REST APIs
- Flyway - Database migrations
- PostgreSQL 15 - Primary database
- HikariCP - Connection pooling
- JPA/Hibernate - ORM
- Grafana 10.1.0 - Dashboards and visualization
- Loki 2.9.0 - Log aggregation
- Promtail 2.9.0 - Log collection
- Logback - Structured logging
- JUnit 5 - Testing framework
- TestContainers - Integration tests
- Mockito - Mocking
- JaCoCo - Code coverage
- Docker & Docker Compose - Containerization
- Maven - Build and dependency management
- OpenAPI 3 - API documentation
- Java 17+ (OpenJDK or Oracle JDK)
- Maven 3.6+ for build and dependency management
- Docker & Docker Compose for complete environment
- Git for repository cloning
# 1. Clone the repository
git clone https://github.com/cristianino/java-product-api.git
cd java-product-api
# 2. Setup environment variables
cp .env.example .env
# Edit .env with your configurations if needed
# 3. Start all services
docker-compose up --build -d
# 4. Verify all services are running
docker-compose ps
# 5. Test the API
curl -H "X-API-Key: dev_api_key_for_local_development_12345" \
http://localhost:8080/api/v1/products
# 1. Setup local PostgreSQL database
# Create 'productdb' database with 'productuser' user
# 2. Configure application-dev.yml with your credentials
# 3. Run the application
mvn spring-boot:run -Dspring-boot.run.profiles=dev
# 4. Run tests
mvn clean test jacoco:report
Once services are running, you'll have access to:
Service | URL | Credentials |
---|---|---|
Product API | http://localhost:8080 | API Key: dev_api_key_for_local_development_12345 |
Swagger UI | http://localhost:8080/swagger-ui.html | - |
Health Check | http://localhost:8080/actuator/health | - |
Grafana | http://localhost:3000 | admin / admin123 |
PostgreSQL | localhost:5432 | productuser / dev_password_123 |
# Database
POSTGRES_DB=productdb
POSTGRES_USER=productuser
POSTGRES_PASSWORD=dev_password_123
# Application
SPRING_PROFILES_ACTIVE=dev
APP_API_KEY=dev_api_key_for_local_development_12345
# Grafana
GRAFANA_ADMIN_PASSWORD=admin123
# JVM (Production)
JAVA_OPTS=-Xms1g -Xmx2g -XX:+UseG1GC
dev
: Local development with detailed logsprod
: Production with structured JSON logstest
: Testing with in-memory database
This service provides two clear API approaches:
# Get all products (simplified format)
curl -H "X-API-Key: your-secret-api-key-here" \
http://localhost:8080/api/internal/products
# Response: {"products": [{"id":1,"name":"Product","price":99.99,"availability":true}], "totalCount":1}
# Get products (JSON:API format)
curl -H "X-API-Key: your-secret-api-key-here" \
-H "Content-Type: application/vnd.api+json" \
http://localhost:8080/api/products
See MICROSERVICE_INTEGRATION.md for complete integration guide.
The API includes connectivity endpoints to verify communication with other microservices, perfect for health checks and integration testing.
# Check connectivity to inventory microservice
curl -H "X-API-Key: your-secret-api-key-here" \
-H "Accept: application/json" \
"http://localhost:8080/api/connectivity/inventory"
Response when inventory is available:
{
"service": "inventory-api",
"status": "UP",
"url": "http://localhost:8082/actuator/health",
"response": {"status": "UP", "components": {...}},
"message": "Successfully connected to Inventory service"
}
Response when inventory is unavailable:
{
"service": "inventory-api",
"status": "DOWN",
"url": "http://localhost:8082/actuator/health",
"error": "Connection refused",
"message": "Failed to connect to Inventory service"
}
# Check status of all connected microservices
curl -H "X-API-Key: your-secret-api-key-here" \
-H "Accept: application/json" \
"http://localhost:8080/api/connectivity/status"
Response:
{
"overall-status": "UP", // UP | DEGRADED
"product-api": {
"service": "product-api",
"status": "UP",
"message": "Product API is running"
},
"inventory-api": {
"service": "inventory-api",
"status": "UP",
"url": "http://localhost:8082/actuator/health",
"response": {...},
"message": "Successfully connected to Inventory service"
},
"timestamp": 1758994357041
}
The connectivity is configured in application.yml
:
microservices:
inventory:
base-url: "http://localhost:8082"
health-endpoint: "/actuator/health"
-
Start Product API:
docker compose -f docker-compose.dev.yml up -d
-
Start Inventory API on port 8082
-
Verify connectivity:
# Should return status: "UP" when both services are running curl -H "X-API-Key: your-secret-api-key-here" \ "http://localhost:8080/api/connectivity/status" | jq .
This connectivity feature is essential for:
- 🏥 Health monitoring in microservice architectures
- 🔍 Integration testing and CI/CD pipelines
- 📊 Service mesh observability
- ⚡ Quick troubleshooting of service dependencies
The API implements URI Path Versioning for clear version management and future scalability.
Base Path: /api/v1/products
Features:
- CRUD operations with JSON:API format
- Basic metadata and links
- Proven stability and reliability
- Foundation for V2.0 development
# Current V1.0 usage
curl -H "X-API-Key: your-secret-api-key-here" \
"http://localhost:8080/api/v1/products"
# Response format:
{
"data": [...],
"links": {"self": "/api/v1/products"},
"meta": {"version": "1.0", "count": 5}
}
Base Path: /api/products
Purpose:
- Simple integration for basic use cases
- Backward compatibility maintained
- Same functionality as V1.0 without version prefix
Future Base Path: /api/v2/products
Planned Enhanced Features:
- ✨ Advanced pagination (
page
,size
,sort
parameters) - ✨ Rich filtering (by name, price range, category)
- ✨ Enhanced metadata (timestamps, performance metrics)
- ✨ Improved HATEOAS links (edit, delete, related resources)
- ✨ Version-specific health endpoint
- ✨ Bulk operations support
- ✨ Enhanced error handling with detailed error codes
Proposed V2.0 Response Format:
{
"data": [...],
"links": {
"self": "/api/v2/products?page=0&size=20",
"first": "/api/v2/products?page=0&size=20",
"last": "/api/v2/products?page=5&size=20",
"next": "/api/v2/products?page=1&size=20"
},
"meta": {
"version": "2.0",
"page": 0,
"size": 20,
"total_pages": 6,
"features": ["pagination", "filtering", "bulk_operations"],
"retrieved_at": "2025-09-27T17:30:22.123Z"
}
}
Use Case | Current Recommendation | Future with V2.0 |
---|---|---|
New integrations | v1 - Stable & proven |
v2 - Enhanced features |
Existing integrations | v1 - No changes needed |
v1 - Maintain compatibility |
Simple use cases | /api/products - Easy setup |
/api/products - Continues working |
The Swagger UI provides separate documentation groups:
- 📖 All Versions: http://localhost:8080/swagger-ui.html
- ✅ V1.0 Products: Select "Products API V1.0 (Current)" group
- ✅ Default Products: Select "Products API (Default)" group
- 🔗 Connectivity: Select "Connectivity & Health" group
For developers ready to implement V2.0, see the comprehensive API Versioning Guide which includes:
- 📋 Complete V2.0 feature specifications
- 🏗️ Step-by-step implementation guide
- 🧩 Controller templates and code examples
- 🧪 Testing strategies and test templates
- 📚 OpenAPI configuration updates
Quick Start for V2.0 Development:
- Review the API_VERSIONING_GUIDE.md
- Create
v2/ProductControllerV2.java
using provided templates - Add enhanced features incrementally
- Update OpenAPI configuration
- Implement comprehensive tests
-
Clone the repository
git clone https://github.com/cristianino/java-product-api.git cd java-product-api
-
Start with Docker (Recommended)
# Development environment with PostgreSQL docker compose -f docker-compose.dev.yml up -d
This starts the API on port 8080 with PostgreSQL
-
Test the APIs
# Test internal API (for microservices) curl -H "X-API-Key: your-secret-api-key-here" \ http://localhost:8080/api/internal/products
-
Access documentation
- Swagger UI: http://localhost:8080/swagger-ui.html
- Health Check: http://localhost:8080/actuator/health
- Health Check: http://localhost:8080/actuator/health
All API endpoints require the X-API-Key
header. Default key: your-secret-api-key-here
curl -X POST http://localhost:8080/api/products \
-H "X-API-Key: your-secret-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"data": {
"type": "products",
"attributes": {
"name": "Laptop",
"price": 999.99
}
}
}'
curl -X GET http://localhost:8080/api/products \
-H "X-API-Key: your-secret-api-key-here"
curl -X GET http://localhost:8080/api/products/1 \
-H "X-API-Key: your-secret-api-key-here"
curl -X PUT http://localhost:8080/api/products/1 \
-H "X-API-Key: your-secret-api-key-here" \
-H "Content-Type: application/json" \
-d '{
"data": {
"type": "products",
"attributes": {
"name": "Updated Laptop",
"price": 1199.99
}
}
}'
curl -X DELETE http://localhost:8080/api/products/1 \
-H "X-API-Key: your-secret-api-key-here"
Variable | Description | Default |
---|---|---|
SPRING_DATASOURCE_URL |
PostgreSQL connection URL | jdbc:postgresql://localhost:5432/productdb |
SPRING_DATASOURCE_USERNAME |
Database username | productuser |
SPRING_DATASOURCE_PASSWORD |
Database password | productpass |
APP_API_KEY |
API key for authentication | your-secret-api-key-here |
SPRING_PROFILES_ACTIVE |
Active profiles | - |
- default: Uses PostgreSQL, console logging
- prod: Uses PostgreSQL, structured JSON logging
- test: Uses H2 in-memory database for testing
# Run all tests with coverage report
mvn clean test jacoco:report
# Run only unit tests
mvn test -Dtest="*Test"
# Run only integration tests
mvn test -Dtest="*IntegrationTest"
# Run tests in Docker
docker run --rm -v $(pwd):/app -w /app maven:3.9-eclipse-temurin-17 mvn clean test jacoco:report
📊 Test Coverage Achieved:
- ✅ 47 tests implemented across all layers
- 🎯 88% instruction coverage (1,204/1,367 instructions)
- � Coverage by Package:
- Infrastructure layer: 100% coverage
- Application UseCase: 96% coverage
- Domain Model: 95% coverage
- Application DTO: 82% coverage
- Domain Service: 42% coverage
- Main Application Class: 37% coverage
📝 Coverage Analysis:
- Target: 90% total coverage
- Current: 88% total coverage
- Gap: 2 percentage points (≈27 instructions)
- Status: Comprehensive test suite with room for domain service improvements
For detailed testing information, see Developer Guide
Database schema is managed with Flyway. Migration scripts are in src/main/resources/db/migration/
.
The application follows these principles:
- Domain-driven design with clear boundaries
- Dependency inversion - domain doesn't depend on infrastructure
- JSON:API specification for consistent API responses
- Comprehensive testing with unit and integration tests
- Endpoint:
/actuator/health
El proyecto incluye un stack completo de observabilidad con Loki y Grafana para visualización de logs centralizada.
- Loki: Agregación de logs centralizada
- Promtail: Recolección de logs de contenedores Docker
- Grafana: Dashboards interactivos para visualización de logs
# Iniciar el stack completo incluyendo observabilidad
docker compose up -d
# Acceder a Grafana
http://localhost:3000
# Usuario: admin, Contraseña: admin123
- 🎯 Grafana Dashboard: http://localhost:3000
- 📊 Loki API: http://localhost:3100
- 🔍 Loki Health: http://localhost:3100/ready
- Java Product API - Logs Dashboard: Visualización completa de logs de la aplicación
- Distribución de niveles de log (INFO, ERROR, WARN, DEBUG)
- Rate de logs por nivel en tiempo real
- Logs de aplicación con búsqueda y filtrado
- Panel específico para logs de ERROR
- Logs estructurados en JSON enviados directamente a Loki
- Etiquetas automáticas:
application=java-product-api
,host
,level
- Metadatos incluidos: timestamp, thread, logger, MDC context, excepciones
- Configuración dual: logs en consola para desarrollo + Loki para producción
Para una guía completa sobre cómo usar los dashboards, interpretar las métricas y personalizar las queries, consulta la Observability Guide.
- Shows application and database health
- Endpoint:
/actuator/metrics
- Standard Spring Boot metrics
- Development: Console logging with colors
- Production: Structured JSON logging for Loki/Grafana integration
docker build -t java-product-api .
docker run -p 8080:8080 \
-e SPRING_DATASOURCE_URL=jdbc:postgresql://host.docker.internal:5432/productdb \
-e SPRING_DATASOURCE_USERNAME=productuser \
-e SPRING_DATASOURCE_PASSWORD=productpass \
java-product-api
Command | Description |
---|---|
docker compose -f docker-compose.dev.yml up -d |
Start full application stack |
mvn clean test jacoco:report |
Run all tests with coverage |
mvn spring-boot:run |
Start application locally |
curl -H "X-API-Key: your-secret-api-key-here" http://localhost:8080/api/v1/products |
Test V1 API (Current & Recommended) |
curl -H "X-API-Key: your-secret-api-key-here" http://localhost:8080/api/products |
Test Default API |
curl -H "X-API-Key: your-secret-api-key-here" http://localhost:8080/api/connectivity/status |
Check microservice connectivity |
curl -H "X-API-Key: your-secret-api-key-here" http://localhost:8080/api/connectivity/inventory |
Check inventory service connection |
📖 Need more details? Check out the comprehensive Developer Guide for:
- 🏗️ Architecture deep-dive
- 🛠️ Environment setup
- 🧪 Testing strategies
- 🔧 API examples
- 🐳 Docker workflows
- 🎯 Troubleshooting
- Current issue: Grafana is included in the same docker-compose as the application
- Recommended solution:
- Move Grafana to a dedicated cluster or separate docker-compose
- Implement Grafana as a managed service (Grafana Cloud or similar)
- Configure dashboards as code with automatic provisioning
- Benefits:
- Separation of concerns between application and observability
- Independent scalability of monitoring tools
- Better management of centralized configurations and dashboards
- Current issue: PostgreSQL running in Docker containers
- Recommended solution:
- AWS RDS PostgreSQL for AWS environments
- Google Cloud SQL for GCP environments
- Azure Database for PostgreSQL for Azure environments
- Implement external connection pooling (PgBouncer)
- Benefits:
- Automatic backups and point-in-time recovery
- High availability and automatic failover
- Managed vertical and horizontal scalability
- Automatic security updates
- Integrated monitoring and alerts
- Istio or Linkerd for microservice communication
- Automatic circuit breakers and retry policies
- Network-level observability (distributed tracing)
- Kong, Ambassador, or AWS API Gateway
- Centralized authentication and rate limiting
- Intelligent routing and load balancing
- Apache Kafka or AWS EventBridge for asynchronous events
- CQRS pattern to separate commands from queries
- Event Sourcing for complete audit trail
- OAuth 2.0 with JWT tokens
- Role-Based Access Control (RBAC)
- Integration with Identity Providers (Auth0, Keycloak)
- HashiCorp Vault or AWS Secrets Manager
- Automatic credential rotation
- Encryption at rest and in transit
- Implement missing tests in Domain Services (currently 42%)
- Mutation testing with PIT
- Contract testing with Pact
- Multi-environment deployment pipeline
- Blue-Green deployments or Canary releases
- Automated rollback on errors
- Redis for distributed caching
- CDN for static content
- Database query optimization and indexing
- Kubernetes for container orchestration
- Horizontal Pod Autoscaler based on metrics
- Distributed session management
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass (
mvn test
) - Check coverage (
mvn jacoco:report
) - Submit a pull request
📋 PR Checklist: All 47 tests passing ✅ | Coverage 88% (Target: 90%) ✅ | Documentation updated ✅
This project is licensed under the MIT License.