Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/jaguililla/hexagonal_spring
Spring template for a REST service designed with Hexagonal architecture
https://github.com/jaguililla/hexagonal_spring
archunit docker docker-compose gatling hexagonal-architecture java kafka paketo-buildpack pitest postgres spring-boot testcontainers
Last synced: 5 days ago
JSON representation
Spring template for a REST service designed with Hexagonal architecture
- Host: GitHub
- URL: https://github.com/jaguililla/hexagonal_spring
- Owner: jaguililla
- License: other
- Created: 2024-06-06T19:16:43.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2024-10-14T16:14:10.000Z (about 1 month ago)
- Last Synced: 2024-10-26T20:34:10.311Z (19 days ago)
- Topics: archunit, docker, docker-compose, gatling, hexagonal-architecture, java, kafka, paketo-buildpack, pitest, postgres, spring-boot, testcontainers
- Language: Java
- Homepage:
- Size: 204 KB
- Stars: 109
- Watchers: 2
- Forks: 11
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.md
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
> # ๐ฏ ABOUT
> This is a 'best practices' template project for Spring Boot with Hexagonal Architecture. However,
> it is an opinionated take on that.
>
> DISCLAIMER: I'm by no means an expert on Spring Boot, one reason to do this is to learn it.
> Opinions are welcomed (with proper reasoning), check the [contributing] section to share your
> thoughts.
>
> The project is mirrored on [GitLab](https://gitlab.com/jaguililla/hexagonal_spring) for CI
> demonstration purposes.
>
> Have fun![contributing]: https://github.com/jaguililla/hexagonal_spring/contribute
# ๐๏ธ Appointments
Example application to create appointments (REST API). Appointments are stored in a relational DB
(Postgres), and their creation/deletion is published to a Kafka broker.## ๐ Architecture
* [Hexagonal]/[Onion]/[Clean] Architecture
* OpenAPI code generation (server and client)[Hexagonal]: https://alistair.cockburn.us/hexagonal-architecture
[Onion]: https://jeffreypalermo.com/2008/07/the-onion-architecture-part-1
[Clean]: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html## ๐งฐ Stack
* Java 21
* Spring 3.3 (configurable server, 'undertow' by default)
* Actuator (healthcheck, etc.)
* Flyway (chosen over Liquibase for its simplicity)
* Postgres
* Kafka## ๐๏ธ Runtime
* Cloud Native Buildpacks (building)
* Docker Compose (local environment with the infrastructure)## ๐งช Test
* ArchUnit (preferred over Java modules: it allows naming checks, etc.)
* Testcontainers (used to provide a test instance of Postgres and Kafka)
* Pitest (mutation testing, nightly)## โ๏ธ Development
* SDKMAN (allows to use simpler runners on CI)
* Maven Wrapper (Maven can be provided by SDKMAN, however, Maven Wrapper has better IDE support)
* Editorconfig (supported by a lot of editors, rules limited though)
* CI pipelines for GitHub and GitLab## ๐ Requirements
* Docker Compose
* JDK 21+
* SDKMAN (optional, recommended)## ๐ค Design Decisions
* Simplicity and pragmatism over Hexagonal Architectures 'by the book'.
* Minimal: don't use libraries to implement easy stuff (even if that's boring).
* Start small, split and refactor when features are added (I.e.: split services into use cases).
* Prefer flat structure (avoid empty parent packages if possible).
* Small coupling with Spring (easier to migrate, to other frameworks/toolkits).
* Not use Spring integrations if a library can be used directly.
* No Spring profiles (settings are loaded from the environment).
* Split API spec in different files for future modularity.
* Prefer service independence over code reuse (sharing libraries among microservices).
* Docker Compose profiles are used to separate infrastructure from a complete local environment.
* Atomicity in notifiers (with outbox pattern) should be done with a different notifier adapter.
* No input ports: they don't need to be decoupled, they just use the domain (and that's acceptable).## ๐ Architecture
![Architecture Diagram](https://raw.githubusercontent.com/jaguililla/hexagonal_spring/main/doc/architecture.svg)
* **Port**: interface to set a boundary between application logic and implementation details.
* **Adapter**: port implementation to connect the application domain with the system's context.
* **Domain**: application logic and model entities.
* **Service**: implement operations with a common topic altogether. Usually calls driven ports.
* **UseCase/Case**: single operation service (isolate features). They can coexist with services.
* **Output/Driven Adapter**: implementation of ports called from the domain.
* **Input/Driver Adapter**: commands that call application logic (don't require a port).## ๐ Design
* The REST API controller and client are generated from the OpenAPI spec at build time.
* `domain` holds business logic (services and/or use cases) and driven ports (interfaces).
* `domain.model` keeps the structures relevant to the application's domain. The more logic added to
an entity, the better (it could be easily accessed by many different services, or use cases).
* `output.{notifiers,repositories}` driven adapters (implementations of driven ports).
* `input.controllers` driver adapter (adapters without interface).
* Subpackages can be created for different adapter implementations (to isolate their code).
* More information about each package rules can be found on their Javadoc documentation.## ๐๏ธ Set up
* With SDKMAN: `sdk env install`
* If SDKMAN is not available, JDK 21+ must be installed.## โถ๏ธ Commands
All commands assume a Unix like OS.The most important commands to operate the project are:
* Build: `./mvnw package`
* Documentation: `./mvnw site`
* Run: `./mvnw spring-boot:run`
* Build image: `./mvnw verify` or `./mvnw spring-boot:build-image`To run or deploy the application:
* Start infrastructure (for running locally): `docker-compose up -d`
* Run JAR locally: `java -jar target/appointments-0.1.0.jar`
* Run container: `docker-compose --profile local up`## ๐ค Service Management
* You can check the API spec using [Swagger UI](http://localhost:8080/swagger-ui/index.html).### Docker
At the `docker-compose.yml` you can find the information on how to run the application as a
container, adjusting the configuration for running it on different environments.Two Docker compose profiles are used:
- Default profile (no profile parameter): to allow starting only the infrastructure, this is useful
to start the application from the IDE
- Local profile (--profile local): which also starts a container using the image of this application### Testing
The verification requests can be executed with: `src/test/resources/requests.sh`, or
`PORT=9090 src/test/resources/requests.sh` if you want to run them to a different port.The health check endpoint is: http://localhost:18080/actuator/health
### Stress Testing (Gatling)
[Gatling settings] can be overridden creating a `gatling.conf` file at the test resources. The
configuration options and their default values can be checked [here][gatlingDefaults].Those parameters can also be overwritten by system properties from the command line. I.e.:
`-D gatling.core.encoding=utf-8`To run the Gatling test, execute `./mvnw gatling:test` at the shell.
[Gatling settings]: https://docs.gatling.io/reference/script/core/configuration
[gatlingDefaults]: https://github.com/gatling/gatling/blob/main/gatling-core/src/main/resources/gatling-defaults.conf