This is a skeleton REST API template project for Spring Boot 3.
Yet another attempt to combine the newest tech stack with a clean architecture.
This project can be used as a starting point for new projects, or as a reference for any Spring Boot 3 based projects.
- Spring Boot 3.3.0
- Gradle 8.5
- PostgreSQL 15 in Docker for local development
- Spring Data JPA as data layer
- Spring MVC for building REST API
- Liquibase 4.27.0 for database migrations
- MapStruct 1.5.5 for mapping data between layers
- Actuator for monitoring and management
- SonarQube 9.9 LTS in Dockerfile with FindBugs plugin installed for local code analysis
- Lombok for reducing boilerplate code
- Jacoco Plugin for code coverage
- Spotbugs Plugin for static code analysis
- SpringDoc OpenApi v2 for API documentation
- Spotless Plugin with google-java-format enabled for code formatting
- Spring Boot DevTools for live restart
- Testcontainers for integration tests
See full list of actual dependencies in build.gradle file.
- Java Development Kit 21 (for example Amazon Corretto or Liberica JDK)
- Docker for local development and testing
- Make utility for your system (optional)
Clone this repository
git clone https://github.com/gigi/gigi-spring-rest-skeleton && cd ./gigi-spring-rest-skeleton
If you have Make utility installed, you can use the following commands:
make run
Alternatively, you can use the following command:
docker-compose up -d postgres && ./gradlew bootRun --args='--spring.profiles.active=dev,sqldebug'
This command will start PostgreSQL 15 using docker-compose.yaml file, build the application and run it on port 8080. Default credentials will be used (postgres:postgres/postgres).
dev
and sqldebug
profiles enables Spring Boot Actuator endpoints, SQL debug logging and expose Swagger endpoint.
After start, you can find the API documentation at http://localhost:8080/docs/swagger-ui/index.html.
If you are using IntelliJ IDEA, add profiles dev
and sqldebug
to the Active profiles
field in
the Run/Debug Configurations
window.
Application shows one of the possible ways to organize a Spring Boot 3 REST API project. API allows users to create/read/update posts, and add tags for these posts. The list of posts can be paginated for easier navigation.
Use docker-compose to start dependencies for local development:
make up
or
./gradlew composeUp
or just
docker-compose up
To shut down dependencies when the work is finished:
make down
or
./gradlew composeDown
or
docker-compose down
Warning: Gradle Docker Compose plugin has issues with container naming so use only one way to start/stop containers.
See avast/gradle-docker-compose-plugin#372 for more information.
The layers in this application are separated from each other, with each layer having its own entities and mappers.
For demonstration purposes, the application uses simple Domain entities: Post and Author represented as Java Records.
Post has a relation to Author just to showcase the potential of the MapStruct mapper. If you are a true DDD fan, it is recommended to use just the AuthorID reference inside the Post aggregate.
The corresponding JPA entities are used only to access data and perform database migrations.
If you don't need to extract pure domain or hate DDD, you can rely solely on JPA classes as a domain layer. It is a common compromise for many projects.
However, it is recommended to stick to immutable entities as much as possible. At the very least, make the public constructor private. Create an all-arguments constructor and avoid using setters. Hibernate will take care of the rest.
The JPA specification itself is not compatible with the classic DDD approach. For more information, please see https://www.baeldung.com/spring-persisting-ddd-aggregates.
The service layer exposes to controller only domain entities, not JPA entities. See ModelMapper.
The presentation layer uses its own mapper to convert business entities to Responses. See ResponseMapper
Migrations are performed using Liquibase and applied on application startup. To create new migration after changing JPA entities against default connected database run:
make migration
or
./gradlew diffChangelog
SQL migration will be created in src/main/resources/db/migrations folder and named according to current time.
By default, credentials from src/main/resources/application.properties will be used. See liquibase task in build.gradle file for more details.
Warning: Do not update liquibase to newer version. It has issues with alter statements. Wait for fix.
Spring Boot 3 introduces support of RFC7807 for REST API error
responses.
This skeleton extends this functionality with custom error codes.
For validation errors additional property violations
added with 422 Unprocessable Entity
status code.
See GlobalExceptionHandler.java
Spotbugs and SonarQube are used for code analysis.
The Spotbugs task is configured to run automatically on every build against main and test source sets.
Filter excludes bugs EI_EXPOSE_REP
and EI_EXPOSE_REP2,MS_EXPOSE_REP
from analysis.
SonarQube is a static code analysis tool. It can be used to detect bugs, vulnerabilities and code smells in your code. It can also measure and track your technical debt.
To analyze the code start SonarQube server from the the docker-compose.yaml file docker-compose up sonarqube
(if not run yet) then run:
./gradlew sonar
This command will analyze the code against Sonar way
quality profile and collect the code coverage. Default admin:admin
credentials are used.
To see the results, open http://localhost:9000 in your browser.
You can change the Quality Profile to Findbugs: For more information see https://www.sonarsource.com/products/sonarqube/
Integration and unit tests run together. To run tests use:
make test
or
./gradlew test
Integration tests rely on Testcontainers library. Use AbstractDataSourceTest.java as starting point. Extend this class with your integration test class (use PostRepositoryTest.java as example).
If you use IntelliJ IDEA, you may configure automatic restart of the application after code changes.
For 2022
and newer versions of IntelliJ IDEA,
open settings and go to Build, Execution, Deployment > Compiler > Build project automatically
. Check the box.
Then go to Advanced Settings, Compiler > Allow auto-make to start even if developed application is currently running
. Check the box.
For more information see https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.devtools.restart
To format the code according to Google Java Style Guide run:
./gradlew spotlessApply
If you want to deploy your application to production using docker, you can build a docker image with this command:
make docker
or
./gradlew clean bootJar && docker build -t gigi/gigi-spring-rest-skeleton:latest .
The docker image will be built using azul/zulu-openjdk-alpine:21-jre. If the image size matters, use jlink to create a custom runtime image.
For more information about containerized java applications please follow:
- https://thecattlecrew.net/2022/11/07/preparing-for-spring-boot-3-choose-the-right-java-17-base-image/
- https://badass-jlink-plugin.beryx.org/releases/latest/
- Add GitHub CI
- Add Spring Security for demonstration purposes
- Update Liquibase when unnecessary alter statements issue will be fixed (liquibase/liquibase#4047)
- Update Gradle to 8.1 when it will be released and tested with Spring Boot 3
- Obtain key for SonarQube instead of password usage
- Separate unit and integration tests