Proof of Concept for a RESTful Web Service built with Spring Boot 4 targeting JDK 25 (LTS). This project demonstrates best practices for building a layered, testable, and maintainable API implementing CRUD operations for a Players resource (Argentina 2022 FIFA World Cup squad).
- Features
- Tech Stack
- Project Structure
- Architecture
- API Endpoints
- Prerequisites
- Quick Start
- Testing
- Docker
- Environment Variables
- Command Summary
- Contributing
- Legal
- π RESTful API - Full CRUD operations for Players resource
- π Clean Architecture - Layered design with clear separation of concerns
- π¦ Input Validation - Bean Validation (JSR-380) constraints
- β‘ Performance Caching - Optimized data retrieval with cache annotations
- π Advanced Search - League search with JPQL and squad number lookup with derived queries
- π Interactive Documentation - Live API exploration and testing interface
- π©Ί Health Monitoring - Application health and metrics endpoints
- β Comprehensive Testing - High code coverage with automated reporting
- π³ Containerized Deployment - Multi-stage builds with pre-seeded database
- π Automated Pipeline - Continuous integration with automated testing and builds
| Component | Technology |
|---|---|
| Framework | Spring Boot 4.0.0 |
| Runtime | Java (JDK 25 LTS) |
| Build Tool | Maven |
| Database (Runtime) | SQLite |
| Database (Tests) | SQLite (in-memory) |
| ORM | Hibernate / Spring Data JPA |
| API Documentation | SpringDoc OpenAPI |
| Testing | JUnit 5 + Mockito + AssertJ |
| Code Coverage | JaCoCo |
| Containerization | Docker + Docker Compose |
| CI/CD | GitHub Actions |
π‘ Note: Maven wrapper (
./mvnw) is included, so Maven installation is optional.
src/main/java/ar/com/nanotaboada/java/samples/spring/boot/
βββ Application.java # Main entry point, @SpringBootApplication
βββ controllers/ # REST endpoints (@RestController)
β βββ PlayersController.java
βββ services/ # Business logic (@Service, caching)
β βββ PlayersService.java
βββ repositories/ # Data access (@Repository, Spring Data JPA)
β βββ PlayersRepository.java
βββ models/ # Domain entities & DTOs
β βββ Player.java # JPA entity
β βββ PlayerDTO.java # Data Transfer Object with validation
βββ converters/ # Infrastructure converters
βββ IsoDateConverter.java # JPA converter for ISO-8601 dates
src/test/java/.../test/
βββ controllers/ # Controller tests (@WebMvcTest)
βββ services/ # Service layer tests
βββ repositories/ # Repository tests (@DataJpaTest)
βββ PlayerFakes.java # Test data factory for Player entities
βββ PlayerDTOFakes.java # Test data factory for PlayerDTO
%%{init: {
"theme": "default",
"themeVariables": {
"fontFamily": "Fira Code, Consolas, monospace",
"textColor": "#555",
"lineColor": "#555",
"lineWidth": 2
}
}}%%
graph BT
%% Core Layers
models[models]
repositories[repositories]
services[services]
controllers[controllers]
%% Framework Features
SpringBoot[Spring Boot]
SpringDataJPA[Spring Data JPA]
SpringCache[Spring Cache]
SpringValidation[Spring Validation]
%% External Dependencies
ProjectLombok[Lombok]
JakartaPersistence[Jakarta Persistence]
ModelMapper[ModelMapper]
SpringDoc[SpringDoc]
%% Tests
tests[tests]
%% Main Application Flow
models --> repositories
models --> services
models --> controllers
repositories --> services
services --> controllers
%% Framework Features connections
SpringBoot --> controllers
SpringBoot --> services
SpringBoot --> repositories
SpringDataJPA --> repositories
SpringCache --> services
SpringValidation --> controllers
%% External Dependencies connections
JakartaPersistence --> models
ProjectLombok --> models
ModelMapper --> services
SpringDoc --> controllers
%% Tests connection (dotted)
controllers -.-> tests
services -.-> tests
repositories -.-> tests
%% Styling
classDef core fill:#b3d9ff,stroke:#6db1ff,stroke-width:2px,color:#555,font-family:monospace;
classDef feat fill:#ffffcc,stroke:#fdce15,stroke-width:2px,color:#555,font-family:monospace;
classDef deps fill:#ffcccc,stroke:#ff8f8f,stroke-width:2px,color:#555,font-family:monospace;
classDef test fill:#ccffcc,stroke:#53c45e,stroke-width:2px,color:#555,font-family:monospace;
class models,repositories,services,controllers core
class SpringBoot,SpringDataJPA,SpringCache,SpringValidation feat
class JakartaPersistence,ProjectLombok,ModelMapper,SpringDoc deps
class tests test
Figure: Core application flow (blue), supporting features (yellow), external dependencies (red), and test coverage (green). Not all dependencies are shown.
Interactive API documentation is available via Swagger UI at http://localhost:9000/swagger/index.html when the server is running.
Quick Reference:
GET /players- List all playersGET /players/{id}- Get player by IDGET /players/search/league/{league}- Search players by leagueGET /players/search/squadnumber/{squadNumber}- Get player by squad numberPOST /players- Create new playerPUT /players/{id}- Update existing playerDELETE /players/{id}- Remove playerGET /actuator/health- Health check
For complete endpoint documentation with request/response schemas, explore the interactive Swagger UI. You can also access the OpenAPI JSON specification at http://localhost:9000/v3/api-docs.
Before you begin, ensure you have the following installed:
- Java Development Kit (JDK) 25
- Maven 3.9+ (optional) - Project includes Maven wrapper (
./mvnw) - Docker (optional) - For containerized deployment
π‘ Note: macOS users may need to set
JAVA_HOME:export JAVA_HOME=$(/usr/libexec/java_home -v 25)
git clone https://github.com/nanotaboada/java.samples.spring.boot.git
cd java.samples.spring.boot./mvnw clean package./mvnw spring-boot:runOnce the application is running, you can access:
- API Server:
http://localhost:9000 - Swagger UI:
http://localhost:9000/swagger/index.html - OpenAPI Spec:
http://localhost:9000/v3/api-docs - Health Check:
http://localhost:9001/actuator/health
Run the full test suite with coverage:
./mvnw verifyView Coverage Report:
open target/site/jacoco/index.htmlTest Structure:
- Unit Tests -
@WebMvcTest,@DataJpaTestfor isolated layer testing (with@AutoConfigureCachefor caching support) - Test Database - SQLite in-memory (jdbc:sqlite::memory:) for fast, isolated test execution
- Mocking - Mockito with
@MockitoBeanfor dependency mocking - Assertions - AssertJ fluent assertions
- Naming Convention -
givenX_whenY_thenZBDD pattern:givenPlayersExist_whenGetAll_thenReturnsOkWithAllPlayers()givenSquadNumberExists_whenPost_thenReturnsConflict()givenPlayerExists_whenFindById_thenReturnsPlayer()
Coverage Targets:
- Controllers: 100%
- Services: 100%
- Repositories: Custom query methods (interfaces excluded by JaCoCo design)
π‘ Note: Dates are stored as ISO-8601 strings for SQLite compatibility. A JPA
AttributeConverterhandles LocalDate β ISO-8601 string conversion transparently. Tests use SQLite in-memory database (jdbc:sqlite::memory:) - the converter works seamlessly with both file-based and in-memory SQLite.
docker compose up
# or detached mode
docker compose up -dExposed Ports:
9000- Main API server9001- Actuator management endpoints
π‘ Note: The Docker container uses a pre-seeded SQLite database with Argentina 2022 FIFA World Cup squad data. On first run, the database is copied from the image to a named volume (
java-samples-spring-boot_storage) ensuring data persistence across container restarts.
docker compose downTo reset the database to its initial state:
docker compose down -v # Remove volumes
docker compose up # Fresh start with seed dataConfiguration in src/main/resources/application.properties:
# Server Configuration
server.port=9000
management.server.port=9001
# Database Configuration (SQLite)
spring.datasource.url=jdbc:sqlite:storage/players-sqlite3.db
spring.datasource.driver-class-name=org.sqlite.JDBC
spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect
spring.jpa.hibernate.ddl-auto=none
# Caching
spring.cache.type=simple
# OpenAPI Documentation
springdoc.api-docs.path=/v3/api-docs
springdoc.swagger-ui.path=/swagger/index.htmlConfiguration in src/test/resources/application.properties:
# Test Database (SQLite in-memory)
spring.datasource.url=jdbc:sqlite::memory:
spring.datasource.driver-class-name=org.sqlite.JDBC
spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect
spring.jpa.hibernate.ddl-auto=create-dropπ‘ Note: Tests use SQLite in-memory database (jdbc:sqlite::memory:) for fast, isolated execution. The ISO-8601 date converter works identically with both file-based and in-memory SQLite.
| Command | Description |
|---|---|
./mvnw clean compile |
Clean and compile the project |
./mvnw test |
Run tests without coverage |
./mvnw verify |
Run tests with JaCoCo coverage |
./mvnw package |
Build JAR file |
./mvnw spring-boot:run |
Run application locally |
./mvnw package -DskipTests |
Build without running tests |
docker compose build |
Build Docker image |
docker compose up |
Start application container |
docker compose up -d |
Start in detached mode |
docker compose down |
Stop and remove containers |
docker compose down -v |
Stop and remove containers with volumes |
docker compose logs -f |
View container logs |
π‘ Note: Always use the Maven wrapper (
./mvnw) instead of system Maven to ensure consistent builds.
Contributions are welcome! Please see CONTRIBUTING.md for details on:
- Code of Conduct
- Development workflow and best practices
- Commit message conventions (Conventional Commits)
- Pull request process and requirements
Key guidelines:
- Follow Conventional Commits for commit messages
- Ensure all tests pass (
./mvnw verify) - Always use Maven wrapper (
./mvnw), never system Maven - Keep changes small and focused
- Review
.github/copilot-instructions.mdfor architectural patterns
This project is provided for educational and demonstration purposes and may be used in production environments at your discretion. All referenced trademarks, service marks, product names, company names, and logos are the property of their respective owners and are used solely for identification or illustrative purposes.