REST API for managing device resources with full CRUD operations, filtering, and comprehensive validation.
The Devices API is a Spring Boot 3.x application that provides a REST interface for managing device resources. It includes features such as:
- Create, read, update (full and partial), and delete devices
- Filter devices by brand and state
- Pagination support for list endpoints
- Comprehensive domain validations
- Full API documentation via Swagger/OpenAPI
- Database persistence with PostgreSQL
- Docker containerization
- Extensive unit and integration tests
- Framework: Spring Boot 3.3.4
- Language: Java 21
- Build Tool: Maven 3.9+
- Database: PostgreSQL 15
- Testing: JUnit 5, Mockito, TestContainers
- Documentation: SpringDoc OpenAPI 3.0 (Swagger)
- Containerization: Docker & Docker Compose
- ORM: Spring Data JPA / Hibernate
devices-api/
├── src/
│ ├── main/
│ │ ├── java/com/devices/
│ │ │ ├── controller/ # REST endpoints
│ │ │ ├── service/ # Business logic
│ │ │ ├── entity/ # JPA entities
│ │ │ ├── repository/ # Data access layer
│ │ │ ├── dto/ # Data transfer objects
│ │ │ ├── exception/ # Custom exceptions
│ │ │ ├── config/ # Configuration classes
│ │ │ ├── util/ # Utility classes
│ │ │ └── DevicesApiApplication.java # Main class
│ │ └── resources/
│ │ ├── application.properties
│ │ ├── application-dev.properties
│ │ └── application-test.properties
│ └── test/
│ ├── java/com/devices/
│ │ ├── service/ # Service unit tests
│ │ ├── controller/ # Controller unit & integration tests
│ │ └── AbstractIntegrationTest.java
│ └── resources/
│ └── application-test.properties
├── Dockerfile # Application container image
├── Dockerfile.postgres # PostgreSQL container image
├── docker-compose.yml # Multi-container orchestration
├── .dockerignore # Docker build exclusions
├── .gitignore # Git exclusions
└── pom.xml # Maven configuration
{
"id": Long, // Unique identifier (auto-generated)
"name": String, // Device name (required, not blank)
"brand": String, // Device brand (required, not blank)
"state": String, // State: AVAILABLE, IN_USE, INACTIVE
"creationTime": LocalDateTime // Immutable creation timestamp
}- AVAILABLE: Device is available for use
- IN_USE: Device is currently in use
- INACTIVE: Device is inactive and unavailable
http://localhost:8080/api/v1/devices
POST /api/v1/devices
Content-Type: application/json
{
"name": "Laptop",
"brand": "Dell"
}
Response: 201 Created
{
"id": 1,
"name": "Laptop",
"brand": "Dell",
"state": "AVAILABLE",
"creationTime": "2025-11-15T20:00:00"
}
GET /api/v1/devices/{id}
Response: 200 OK
{
"id": 1,
"name": "Laptop",
"brand": "Dell",
"state": "AVAILABLE",
"creationTime": "2025-11-15T20:00:00"
}
GET /api/v1/devices?page=0&size=10&sort=id,desc
Response: 200 OK
{
"content": [...],
"pageable": {...},
"totalPages": 1,
"totalElements": 5,
...
}
GET /api/v1/devices/brand/{brand}?page=0&size=10
Response: 200 OK
{
"content": [...],
"pageable": {...},
...
}
GET /api/v1/devices/state/{state}?page=0&size=10
Valid states: AVAILABLE, IN_USE, INACTIVE
Response: 200 OK
{
"content": [...],
"pageable": {...},
...
}
PUT /api/v1/devices/{id}
Content-Type: application/json
{
"name": "Laptop Pro",
"brand": "Dell",
"state": "AVAILABLE"
}
Response: 200 OK
{
"id": 1,
"name": "Laptop Pro",
"brand": "Dell",
"state": "AVAILABLE",
"creationTime": "2025-11-15T20:00:00"
}
PATCH /api/v1/devices/{id}
Content-Type: application/json
{
"state": "INACTIVE"
}
Response: 200 OK
{
"id": 1,
"name": "Laptop",
"brand": "Dell",
"state": "INACTIVE",
"creationTime": "2025-11-15T20:00:00"
}
DELETE /api/v1/devices/{id}
Response: 204 No Content
- creationTime: Cannot be updated after creation (set via @PrePersist)
- Name/Brand Updates: Cannot update name or brand if device is IN_USE
- Deletion: Cannot delete a device that is IN_USE
- name: Required, non-blank
- brand: Required, non-blank
- state: Must be valid enum value (AVAILABLE, IN_USE, INACTIVE)
{
"timestamp": "2025-11-15T20:00:00",
"status": 400,
"error": "Validation Failed",
"message": "One or more validation errors occurred",
"validationErrors": {
"name": "Device name is required"
},
"path": "/api/v1/devices"
}{
"timestamp": "2025-11-15T20:00:00",
"status": 400,
"error": "Bad Request",
"message": "Cannot update name or brand of a device that is IN_USE",
"path": "/api/v1/devices/1"
}{
"timestamp": "2025-11-15T20:00:00",
"status": 404,
"error": "Not Found",
"message": "Device not found with id: 999",
"path": "/api/v1/devices/999"
}- Java 21 or higher
- Maven 3.9 or higher (or use
./mvnw) - Docker & Docker Compose (for containerized setup)
- PostgreSQL 15 (for local setup without Docker)
- Clone the repository
git clone https://github.com/your-username/devices-api.git
cd devices-api- Start PostgreSQL (Docker or local installation)
# Using Docker
docker run --name devices-postgres \
-e POSTGRES_DB=devices_db \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
postgres:15-alpine- Build the application
mvn clean install- Run the application
mvn spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=dev"- Access the API
- API: http://localhost:8080/api/v1/devices
- Swagger UI: http://localhost:8080/swagger-ui.html
- OpenAPI spec: http://localhost:8080/v3/api-docs
- Build and run with Docker Compose
docker-compose up -dThis will:
- Start PostgreSQL container with volume persistence
- Build and start the Spring Boot application
- Create necessary networks and volumes
- Access the application
- View logs
docker-compose logs -f app- Stop the containers
docker-compose down- Clean up volumes (removes database data)
docker-compose down -vmvn testmvn test -DskipITs -Dtest="DeviceServiceTest,DeviceControllerTest"mvn failsafe:integration-test failsafe:verifyNote: Integration tests use TestContainers and require Docker to be running.
mvn clean test jacoco:report- Unit Tests: 23 tests (DeviceServiceTest, DeviceControllerTest)
- Integration Tests: 9 tests (DeviceControllerIT with TestContainers)
- Total Tests: 32 comprehensive test cases
- Test Status: All tests passing ✅
Used for general development with basic configuration.
Development profile with:
- Formatted SQL logging
- DEBUG level logging for application code
- Full SQL parameter logging
- Drop and recreate database on startup
Run with: --spring.profiles.active=dev
Used automatically during test execution with TestContainers PostgreSQL.
# PostgreSQL
spring.datasource.url=jdbc:postgresql://localhost:5432/devices_db
spring.datasource.username=postgres
spring.datasource.password=postgresspring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialectAccess the interactive API documentation at:
http://localhost:8080/swagger-ui.html
View the raw OpenAPI 3.0 specification at:
http://localhost:8080/v3/api-docs
- Controller Layer (
DeviceController): Handles HTTP requests, validation, and responses - Service Layer (
DeviceService): Contains business logic and domain validations - Repository Layer (
DeviceRepository): Data access with custom JPQL queries - Entity Layer (
Device): JPA-mapped domain entity
- DTO Pattern: Separation of API contracts from domain entities
- Builder Pattern: Flexible object construction (Lombok @Builder)
- Repository Pattern: Abstraction of data access logic
- Exception Handling: Centralized global exception handler (@ControllerAdvice)
- Bean Validation: Request-level validation with @Valid annotations
- Domain Validation: Service-level business rule validation
- Entity Validation: JPA annotations for column constraints
- Add JWT token-based authentication
- Implement role-based access control (RBAC)
- Add request rate limiting
- Implement distributed tracing with Spring Cloud Sleuth
- Add metrics collection with Micrometer/Prometheus
- Configure centralized logging (ELK stack)
- Add database migration tool (Flyway or Liquibase)
- Implement soft delete capability
- Add audit trail (createdBy, updatedBy, updatedAt)
- Add database indexes for performance
- Implement sorting on all endpoints
- Add advanced filtering (device properties)
- Add bulk operations (bulk update/delete)
- Implement HATEOAS for discoverability
- Add performance/load testing
- Implement API contract testing
- Add chaos engineering tests
- Increase coverage to 90%+
- Add GitHub Actions CI/CD pipeline
- Implement Kubernetes manifests (Helm charts)
- Add SonarQube integration for code quality
- Configure automated security scanning
- No Authentication: API is currently open without authentication
- No Pagination HATEOAS: Page responses use Spring Data's PageImpl (warning logged)
- DDL Auto: Using
create-drop- recreates schema on each startup - No Soft Delete: Deletions are permanent
- Limited Audit Trail: Only creation time tracked
- TestContainers Startup Time: Integration tests may take longer due to container initialization
- Database Locking: No optimistic/pessimistic locking mechanism
- No Caching: All queries hit the database
If port 8080 is already in use:
# Change port
mvn spring-boot:run -Dspring-boot.run.arguments="--server.port=8081"# Verify PostgreSQL is running
psql -U postgres -d devices_db
# Check connection string in application-dev.properties# Clear Docker resources
docker system prune -a
# Rebuild without cache
docker-compose build --no-cache- Create feature branches for new features
- Follow conventional commits format
- Ensure all tests pass before submitting PR
- Maintain test coverage above 70%
- Update documentation as needed
MIT License - see LICENSE file for details
For issues, questions, or suggestions, please open an issue on GitHub or contact the development team.
Last Updated: November 16, 2025
Version: 1.0.0
Status: Production Ready ✅