A Spring Boot 4 REST API for managing a library's book inventory and member checkout operations.
| Component | Version |
|---|---|
| Java | JDK 25 |
| Spring Boot | 4.0.2 |
| Spring Security | 7.x |
| PostgreSQL | 16+ |
| H2 Database | (dev/test) |
| JWT Authentication | jjwt 0.12.6 |
| Build Tool | Maven |
- Book Management (ADMIN): CRUD operations for library books
- Member Checkout (MEMBER): Browse available books, checkout, and return
- JWT Authentication: Secure token-based authentication
- Role-Based Access Control: ADMIN and MEMBER roles
- Pagination: All list endpoints support pagination
- Validation: Comprehensive input validation
src/main/java/com/library/
├── LibraryManagementApplication.java # Main entry point
├── application/ # Application layer
│ ├── dto/ # Data Transfer Objects
│ ├── mapper/ # Entity-DTO mappers
│ └── service/ # Business logic
├── domain/ # Domain layer
│ ├── exception/ # Custom exceptions
│ ├── model/ # Entities and enums
│ └── repository/ # Data access interfaces
├── infrastructure/ # Infrastructure layer
│ ├── config/ # Configuration classes
│ └── security/ # JWT security
└── presentation/ # Presentation layer
├── advice/ # Exception handlers
└── controller/ # REST controllers
- JDK 25 or later
- Maven 3.9+
- PostgreSQL 16+ (for staging/production)
Run with H2 in-memory database, debug logging, and sample data:
# Unix/Linux/macOS
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev
# Windows PowerShell
.\mvnw spring-boot:run "-Dspring-boot.run.profiles=dev"
# Windows Command Prompt
.\mvnw spring-boot:run -Dspring-boot.run.profiles=devThe application will start on http://localhost:8080 with:
- H2 in-memory database (data resets on restart)
- Sample data pre-loaded (users and books)
- H2 Console available at
/h2-console - Debug logging enabled
- SQL queries logged to console
Run with PostgreSQL database and Flyway migrations:
# Unix/Linux/macOS
./mvnw spring-boot:run -Dspring-boot.run.profiles=staging
# Windows PowerShell
.\mvnw spring-boot:run "-Dspring-boot.run.profiles=staging"Required environment variables:
# Unix/Linux/macOS
export DATABASE_URL=jdbc:postgresql://localhost:5432/library_staging
export DATABASE_USERNAME=your_username
export DATABASE_PASSWORD=your_password
export JWT_SECRET=your-256-bit-secret-key-for-staging# Windows PowerShell
$env:DATABASE_URL="jdbc:postgresql://localhost:5432/library_staging"
$env:DATABASE_USERNAME="your_username"
$env:DATABASE_PASSWORD="your_password"
$env:JWT_SECRET="your-256-bit-secret-key-for-staging"Features:
- PostgreSQL database with Flyway migrations
- Info-level logging
- Connection pooling optimized for staging
Run with production-optimized settings:
# Unix/Linux/macOS
./mvnw spring-boot:run -Dspring-boot.run.profiles=prod
# Windows PowerShell
.\mvnw spring-boot:run "-Dspring-boot.run.profiles=prod"
# Using Java directly (recommended for production)
java -jar target/library-management-system-1.0.0-SNAPSHOT.jar --spring.profiles.active=prodRequired environment variables:
# Unix/Linux/macOS
export DATABASE_URL=jdbc:postgresql://localhost:5432/library_prod
export DATABASE_USERNAME=your_username
export DATABASE_PASSWORD=your_password
export JWT_SECRET=your-256-bit-secret-key-for-production
export SERVER_PORT=8080# Windows PowerShell
$env:DATABASE_URL="jdbc:postgresql://localhost:5432/library_prod"
$env:DATABASE_USERNAME="your_username"
$env:DATABASE_PASSWORD="your_password"
$env:JWT_SECRET="your-256-bit-secret-key-for-production"
$env:SERVER_PORT="8080"Features:
- PostgreSQL database with Flyway migrations
- Minimal logging (WARN level)
- Optimized connection pooling
- Graceful shutdown enabled
- Virtual threads enabled for high concurrency
| Username | Password | Role |
|---|---|---|
| admin | admin123 | ADMIN |
| member | member123 | MEMBER |
| Method | Endpoint | Description | Access |
|---|---|---|---|
| POST | /api/v1/auth/login |
User login | Public |
| POST | /api/v1/auth/refresh |
Refresh token | Public |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/books |
Create a new book |
| GET | /api/v1/books |
List all books (paginated) |
| GET | /api/v1/books/{id} |
Get book by ID |
| PUT | /api/v1/books/{id} |
Update a book |
| DELETE | /api/v1/books/{id} |
Delete a book |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/books/available |
List available books |
Query Parameters:
genre: Filter by genre (FICTION, NON_FICTION, SCIENCE, HISTORY, BIOGRAPHY, CHILDREN)publicationYear: Filter by publication yearpage: Page number (default: 0)size: Page size (default: 20)
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/checkouts/books/{bookId} |
Checkout a book |
| POST | /api/v1/checkouts/{checkoutId}/return |
Return a book |
| GET | /api/v1/checkouts/history |
Get checkout history |
POST /api/v1/auth/login
{
"username": "member",
"password": "member123"
}{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600
}Include the access token in the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# Unix/Linux/macOS (curl)
curl -X POST http://localhost:8080/api/v1/books \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"isbn": "978-0-06-112008-4",
"title": "To Kill a Mockingbird",
"author": "Harper Lee",
"genre": "FICTION",
"publicationYear": 1960,
"totalCopies": 5
}'# Windows PowerShell
Invoke-RestMethod -Uri "http://localhost:8080/api/v1/books" `
-Method POST `
-Headers @{
"Authorization" = "Bearer <admin-token>"
"Content-Type" = "application/json"
} `
-Body '{
"isbn": "978-0-06-112008-4",
"title": "To Kill a Mockingbird",
"author": "Harper Lee",
"genre": "FICTION",
"publicationYear": 1960,
"totalCopies": 5
}'# Unix/Linux/macOS (curl)
curl "http://localhost:8080/api/v1/books/available?genre=FICTION&page=0&size=10" \
-H "Authorization: Bearer <member-token>"# Windows PowerShell
Invoke-RestMethod -Uri "http://localhost:8080/api/v1/books/available?genre=FICTION&page=0&size=10" `
-Headers @{ "Authorization" = "Bearer <member-token>" }# Unix/Linux/macOS (curl)
curl -X POST http://localhost:8080/api/v1/checkouts/books/{bookId} \
-H "Authorization: Bearer <member-token>"# Windows PowerShell
Invoke-RestMethod -Uri "http://localhost:8080/api/v1/checkouts/books/{bookId}" `
-Method POST `
-Headers @{ "Authorization" = "Bearer <member-token>" }# Unix/Linux/macOS (curl)
curl -X POST http://localhost:8080/api/v1/checkouts/{checkoutId}/return \
-H "Authorization: Bearer <member-token>"# Windows PowerShell
Invoke-RestMethod -Uri "http://localhost:8080/api/v1/checkouts/{checkoutId}/return" `
-Method POST `
-Headers @{ "Authorization" = "Bearer <member-token>" }| Variable | Description | Default |
|---|---|---|
SPRING_PROFILES_ACTIVE |
Active profile (dev/staging/prod) | dev |
SERVER_PORT |
Server port | 8080 |
DATABASE_URL |
PostgreSQL connection URL | - |
DATABASE_USERNAME |
Database username | - |
DATABASE_PASSWORD |
Database password | - |
JWT_SECRET |
JWT signing secret (256+ bits) | - |
JWT_ACCESS_EXPIRATION |
Access token expiration (ms) | 3600000 |
JWT_REFRESH_EXPIRATION |
Refresh token expiration (ms) | 86400000 |
- dev: H2 in-memory database, debug logging, sample data
- staging: PostgreSQL, info logging, Flyway migrations
- prod: PostgreSQL, optimized settings, minimal logging
# Unix/Linux/macOS
./mvnw test
# Windows PowerShell / Command Prompt
.\mvnw test# Unix/Linux/macOS
./mvnw verify
# Windows PowerShell / Command Prompt
.\mvnw verifyCoverage report will be available at target/site/jacoco/index.html
The project enforces a minimum 80% line coverage requirement via JaCoCo. The build will fail if coverage drops below this threshold.
Current test coverage includes:
| Layer | Classes Tested |
|---|---|
| Application Services | BookService, CheckoutService, AuthService, UserService |
| Mappers | BookMapper, CheckoutMapper |
| Controllers | BookController, CheckoutController, AuthController |
| Security | JwtTokenProvider, JwtAuthenticationFilter |
| Filters | RequestTracingFilter |
| Domain Models | Book, User, Checkout |
src/test/java/com/library/
├── application/
│ ├── mapper/ # Mapper unit tests
│ └── service/ # Service unit tests
├── domain/
│ └── model/ # Domain model tests
├── infrastructure/
│ └── security/ # Security component tests
└── presentation/
├── controller/ # Controller tests (MockMvc)
└── filter/ # Filter unit tests
- Book Deletion/Update: Books with active checkouts cannot be deleted or updated
- Checkout Duration: Default checkout period is 14 days
- Return Ownership: Members can only return their own checkouts
- ISBN Uniqueness: Each book must have a unique ISBN
- Available Copies: Checkout decrements available copies; return increments
The API uses RFC 7807 Problem Detail format for errors:
{
"type": "https://api.library.com/errors/not-found",
"title": "Resource Not Found",
"status": 404,
"detail": "Book with ID abc123 not found",
"timestamp": "2025-01-15T10:30:00Z",
"resourceType": "Book",
"identifier": "abc123"
}This project is for demonstration purposes.