A comprehensive RESTful API for managing books and authors built with Spring Boot 3.1, demonstrating modern Spring Framework patterns, JPA/Hibernate ORM, and PostgreSQL integration.
This application follows a layered architecture pattern with clear separation of concerns:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β REST Controllers β
β (AuthorController, BookController) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Service Layer β
β (AuthorService, BookService) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Repository Layer β
β (Spring Data JPA Repositories) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Domain Layer β
β (Entities, DTOs, Mappers) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Data Persistence β
β (PostgreSQL Database) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Java 17 - Latest LTS version with modern language features
- Spring Boot 3.1.0 - Enterprise-grade application framework
- Spring Data JPA - Repository abstraction over JPA/Hibernate
- Hibernate - ORM framework for database operations
- PostgreSQL - Production-grade relational database
- Maven 3.9.2 - Dependency management and build automation
- Lombok - Annotation processor for reducing boilerplate code
- ModelMapper 3.0.0 - Object mapping framework
- H2 Database - In-memory database for testing
- Spring Boot Test - Comprehensive testing framework
- Docker Compose - Container orchestration for development
βββββββββββββββββββ βββββββββββββββββββ
β AuthorEntity β β BookEntity β
βββββββββββββββββββ€ βββββββββββββββββββ€
β id (PK) βββββββββ β isbn (PK) β
β name β β β title β
β age β βββ authorEntity β
βββββββββββββββββββ βββββββββββββββββββ
CREATE TABLE authors (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255),
age INTEGER
);
CREATE TABLE books (
isbn VARCHAR(255) PRIMARY KEY,
title VARCHAR(255),
author_id BIGINT REFERENCES authors(id)
);
src/
βββ main/
β βββ java/com/testpjt/database/
β β βββ BooksApiApplication.java # Main application class
β β βββ config/
β β β βββ MapperConfig.java # ModelMapper configuration
β β βββ controllers/ # REST endpoints
β β β βββ AuthorController.java
β β β βββ BookController.java
β β βββ domain/
β β β βββ dto/ # Data Transfer Objects
β β β β βββ AuthorDto.java
β β β β βββ BookDto.java
β β β βββ entities/ # JPA entities
β β β βββ AuthorEntity.java
β β β βββ BookEntity.java
β β βββ mappers/ # Object mapping
β β β βββ Mapper.java
β β β βββ impl/
β β β βββ AuthorMapperImpl.java
β β β βββ BookMapperImpl.java
β β βββ repositories/ # Data access layer
β β β βββ AuthorRepository.java
β β β βββ BookRepository.java
β β βββ services/ # Business logic
β β βββ AuthorService.java
β β βββ BookService.java
β β βββ impl/
β β βββ AuthorServiceImpl.java
β β βββ BookServiceImpl.java
β βββ resources/
β βββ application.properties # Production configuration
β βββ banner.txt # Custom application banner
βββ test/
βββ java/com/testpjt/database/
β βββ BooksApiApplicationTests.java
β βββ TestDataUtil.java
β βββ controllers/ # Integration tests
β β βββ AuthorControllerIntegrationTests.java
β β βββ BooksControllerIntegrationTests.java
β βββ repositories/ # Repository tests
β βββ AuthorEntityRepositoryIntegrationTests.java
β βββ BookEntityRepositoryIntegrationTests.java
βββ resources/
βββ application.properties # Test configuration (H2)
- Java 17 or higher
- Docker & Docker Compose (for PostgreSQL)
- Maven 3.6+ (or use included wrapper)
-
Clone the repository
git clone <repository-url> cd testpjt
-
Start PostgreSQL with Docker Compose
docker-compose up -d
This starts PostgreSQL on port
5433
with credentials:- Host:
localhost:5433
- Database:
postgres
- Username:
postgres
- Password:
changemeinprod!
- Host:
-
Build the application
./mvnw clean compile
-
Run tests
./mvnw test
-
Start the application
./mvnw spring-boot:run
The application will start on http://localhost:8080
POST /authors
Content-Type: application/json
{
"name": "J.K. Rowling",
"age": 58
}
GET /authors
GET /authors/{id}
PUT /authors/{id}
Content-Type: application/json
{
"name": "Joanne Rowling",
"age": 59
}
PATCH /authors/{id}
Content-Type: application/json
{
"age": 59
}
DELETE /authors/{id}
PUT /books/{isbn}
Content-Type: application/json
{
"title": "Harry Potter and the Philosopher's Stone",
"author": {
"id": 1,
"name": "J.K. Rowling",
"age": 58
}
}
GET /books
GET /books/{isbn}
PATCH /books/{isbn}
Content-Type: application/json
{
"title": "Harry Potter and the Sorcerer's Stone"
}
DELETE /books/{isbn}
- Auto-configuration for JPA, web, and data source
- Component scanning with
@SpringBootApplication
- Profile-based configuration (development vs test)
- JPA/Hibernate for ORM with annotation-based configuration
- PostgreSQL for production with custom port configuration
- H2 in-memory database for testing
- Automatic DDL generation with
spring.jpa.hibernate.ddl-auto=update
- Spring Data JPA repositories extending
CrudRepository
- Custom query methods with method naming conventions
- JPQL queries with
@Query
annotation - Pagination support with
PagingAndSortingRepository
- Interface-based services for loose coupling
- Dependency injection with constructor injection
- Business logic encapsulation separate from controllers
- Exception handling with runtime exceptions
- RESTful endpoints following HTTP semantics
- Proper HTTP status codes (200, 201, 404, etc.)
- Request/Response mapping with
@RequestBody
and@ResponseEntity
- Path variables with
@PathVariable
- ModelMapper for entity-DTO conversion
- Custom mapper interfaces for type safety
- Loose matching strategy for flexible field mapping
- Bidirectional mapping (entity β DTO)
- Integration tests with
@SpringBootTest
- Repository tests with
@DataJpaTest
- Test data utilities for consistent test setup
- H2 database for isolated test execution
# Database Configuration
spring.datasource.url=jdbc:postgresql://localhost:5433/postgres
spring.datasource.username=postgres
spring.datasource.password=changemeinprod!
spring.datasource.driver-class-name=org.postgresql.Driver
# JPA/Hibernate Configuration
spring.jpa.hibernate.ddl-auto=update
# H2 In-Memory Database
spring.datasource.url=jdbc:h2:mem:testdb;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE;DEFAULT_NULL_ORDERING=HIGH
spring.datasource.username=sa
spring.datasource.password=password
spring.datasource.driver-class-name=org.h2.Driver
The project includes Docker Compose configuration for easy PostgreSQL setup:
version: "3.1"
services:
db:
image: postgres
ports:
- "5433:5432"
restart: always
environment:
POSTGRES_PASSWORD: changemeinprod!
# Run all tests
./mvnw test
# Run specific test class
./mvnw test -Dtest=AuthorControllerIntegrationTests
# Run with coverage
./mvnw test jacoco:report
- Unit Tests - Service layer logic
- Integration Tests - Controller endpoints with database
- Repository Tests - JPA repository functionality
- Entity relationships properly mapped with JPA annotations
- Lazy loading for associated entities
- Query optimization with custom JPQL queries
- Connection pooling handled by Spring Boot defaults
- Stateless services for horizontal scalability
- DTO pattern to reduce data transfer overhead
- Efficient object mapping with ModelMapper
- Proper HTTP caching headers in responses
- Basic Spring Security configuration (implicit)
- Database credentials in configuration files
- No authentication/authorization implemented
- Implement Spring Security for authentication
- Use environment variables for sensitive configuration
- Add input validation and sanitization
- Implement rate limiting and CORS policies
π The API is currently deployed and accessible at:
https://container-service-1.rgaj2b5egkhqr.ap-southeast-1.cs.amazonlightsail.com/
Base URL for API endpoints:
- Authors:
https://container-service-1.rgaj2b5egkhqr.ap-southeast-1.cs.amazonlightsail.com/authors
- Books:
https://container-service-1.rgaj2b5egkhqr.ap-southeast-1.cs.amazonlightsail.com/books
This application is deployed on Amazon Lightsail Container Service in the ap-southeast-1
region, providing a scalable and cost-effective cloud hosting solution.
- Auto-scaling: Container service automatically scales based on demand
- Load balancing: Built-in load balancer for high availability
- HTTPS: Automatic SSL/TLS certificate management
- Regional deployment: Asia Pacific (Singapore) region for optimal performance
- Container orchestration: Managed container environment
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Amazon Lightsail β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Container Service β β
β β βββββββββββββββββββ βββββββββββββββββββ β β
β β β Spring Boot β β PostgreSQL β β β
β β β Application βββββΊβ Database β β β
β β β (JAR) β β Container β β β
β β βββββββββββββββββββ βββββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β² β
β β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Load Balancer + HTTPS β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β²
β
HTTPS Traffic from Internet
# Clean and build the application
./mvnw clean package
# The JAR file will be created at:
# target/database-0.0.1-SNAPSHOT.jar
# Run the JAR locally
java -jar target/database-0.0.1-SNAPSHOT.jar
# Run with custom port
java -jar -Dserver.port=8080 target/database-0.0.1-SNAPSHOT.jar
# Run with production profile
java -jar -Dspring.profiles.active=prod target/database-0.0.1-SNAPSHOT.jar
Property | Value |
---|---|
File Name | database-0.0.1-SNAPSHOT.jar |
Location | target/database-0.0.1-SNAPSHOT.jar |
Type | Spring Boot Fat JAR (executable) |
Size | ~50-70 MB (includes all dependencies) |
Java Version | Requires Java 17+ |
FROM openjdk:17-jre-slim
# Set working directory
WORKDIR /app
# Copy the JAR file
COPY target/database-0.0.1-SNAPSHOT.jar app.jar
# Expose port
EXPOSE 8080
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
# Run the application
ENTRYPOINT ["java", "-jar", "app.jar"]
# Build Docker image
docker build -t books-api .
# Tag for Lightsail (replace with your service name)
docker tag books-api:latest books-api:latest
# Push to Lightsail Container Service
aws lightsail push-container-image \
--service-name container-service-1 \
--label books-api \
--image books-api:latest
# Database Configuration
export SPRING_DATASOURCE_URL=jdbc:postgresql://prod-db:5432/books_db
export SPRING_DATASOURCE_USERNAME=prod_user
export SPRING_DATASOURCE_PASSWORD=secure_password
# Application Configuration
export SPRING_PROFILES_ACTIVE=prod
export SERVER_PORT=8080
# Lightsail specific
export JAVA_OPTS="-Xmx512m -Xms256m"
{
"containers": {
"books-api": {
"image": ":books-api.latest",
"ports": {
"8080": "HTTP"
},
"environment": {
"SPRING_DATASOURCE_URL": "jdbc:postgresql://db:5432/books_db",
"SPRING_DATASOURCE_USERNAME": "postgres",
"SPRING_DATASOURCE_PASSWORD": "your_password",
"SPRING_PROFILES_ACTIVE": "prod"
}
}
},
"publicEndpoint": {
"containerName": "books-api",
"containerPort": 8080,
"healthCheck": {
"healthyThreshold": 2,
"unhealthyThreshold": 2,
"timeoutSeconds": 5,
"intervalSeconds": 30,
"path": "/actuator/health"
}
}
}
After deployment, verify the API is working:
# Check health endpoint
curl https://container-service-1.rgaj2b5egkhqr.ap-southeast-1.cs.amazonlightsail.com/actuator/health
# Test authors endpoint
curl https://container-service-1.rgaj2b5egkhqr.ap-southeast-1.cs.amazonlightsail.com/authors
# Test books endpoint
curl https://container-service-1.rgaj2b5egkhqr.ap-southeast-1.cs.amazonlightsail.com/books