gigi / gigi-spring-rest-skeleton

❤️‍🔥 Spring Boot 3 template project pre-configured with REST API, PostgreSQL, static analysis tools and testing environment.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Spring Boot 3 REST API skeleton

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.

Table of contents

Note: I recommend using Spring Boot 2.7.x for new enterprise projects as of March 2023. Spring Boot 2.7.x has more stable dependencies and more relevant examples available online, especially for working with JPA and Hibernate 6. This is based on my personal experience working with this skeleton.

What's included

See full list of actual dependencies in build.gradle file.

Requirements

Quick start

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.

Swagger UI

If you are using IntelliJ IDEA, add profiles dev and sqldebug to the Active profiles field in the Run/Debug Configurations window.

IntelliJ IDEA run configurations

Overview

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.

Local development

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.

Data model and domain

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

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.

Problem Details for HTTP APIs (RFC7807)

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

Code analysis

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

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.

SonarQube analysis

You can change the Quality Profile to Findbugs: SonarQube quality gate For more information see https://www.sonarsource.com/products/sonarqube/

Testing

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).

Live restart

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

Code formatting

To format the code according to Google Java Style Guide run:

./gradlew spotlessApply

Production build

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:17-jre. If the image size matters, use jlink to create a custom runtime image.

For more information about containerized java applications please follow:

TODO

  • 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

About

❤️‍🔥 Spring Boot 3 template project pre-configured with REST API, PostgreSQL, static analysis tools and testing environment.

License:MIT License


Languages

Language:Java 96.3%Language:Makefile 1.9%Language:Dockerfile 1.7%