From 994066b856d70b3f5e374e07e25d614992d300d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=A4nel?= Date: Tue, 12 Aug 2025 17:29:18 +0200 Subject: [PATCH] docs: add README --- README.md | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..ee5a7af --- /dev/null +++ b/README.md @@ -0,0 +1,133 @@ +# Recipe API +A reactive REST API for managing recipes. +I started this project after finishing my course +on [Java Backend Development with Spring Boot at Hyperskill](https://hyperskill.org/courses/12). +It's main purpose is to serve as a more practical place for learning and applying furthers +aspects of backend web development with Spring Boot and Java. + +## Learning +### Goals +- Understand and implement asynchronous programming principles with Project Reactor and Spring +- Acquire more knowledge about common testing strategies and apply them with Spring, JUnit & AssertJ +- Practice database design and SQL queries with PostgresSQL +- Gain some experience with Spring Security +- Identify the strengths, weaknesses, idioms, and common pitfalls of programming in Java +- Try out project Lombok + +### Thoughts and Observations +**Reactive web development with Spring WebFlux, R2DBC and Project Reactor** +- main expected advantage is performance, primarily due to non-blocking I/O +- out of the box reactive operators seem strong (e.g. buffering/timeouts) + - i didn't feel the urge to use them yet, as this project doesn't have real-world workloads. +- seems like a good fit for event/message based application parts +- implementing a servlet web application instead would probably make initial development faster + - currently better integration within the ecosystem e.g. with Spring Data JPA + - might not be as scalable in the long run + - migrating a complex monolithic servlet application to reactive stack seems like a hard task +- microservice approach could be helpful in practice + - event-based and performance critical sections in reactive web app + - remaining code in servlet web app + - allows for future replacements with implementations in other programming languages/frameworks + (when performance/cost concerns arise) +- current project idea doesn't have use-cases where event-based programming was necessary +- code for complex reactive chains can quickly become convoluted + - reactive streams integrate asynchronous code through functional composition + - no syntax-based conveniences in Java (such as `async`/`await` in other languages) +- documentation for the reactive stack still feels less comprehensive in some areas compared to + servlet-based applications. + +**Testing practices** +- no declarative transaction support for reactive tests +- tests should also be reactive to support all test cases and transaction rollback +- helper classes can be used to accumulate more than two variables for assertions + - makes test implementation more straightforward + - using tuples with more than two variables gets unwieldy quickly due to code repetition +- all objects of the reactive result chain need to be valid publishers (e.g. `Mono`/`Flux`) + - mocks require specification of when cases for all participating methods +- adding facades for certain parts of the application allows more code to stay testable + - extracting`UserPrincipal` from a request from a facade instead of `@AuthenticationPrincipal` + - obtaining current time from a facade instead of using `Instant.now()` + +**Database layer with Postgres** +- choosing Postgres offers a wide range of built-in functions and extensions. +- keeping data generation within the application code simplifies integration with derived queries +- Spring R2DBC has some limits + - `@Query` can only be used with builtin positional arguments (`$1`, `$2`) + - no easy support of composite keys in `ReactiveCrudRepository` + - m-to-n relationship entities additionally need their own keys + +**Spring Security** +- implementing custom authorization has a steep learning curve +- no architecture explanation for reactive applications within the Spring Security reference + documentation +- gaining manual understanding through API documentation is more time-consuming +- there is room for improvement in understanding all potential consequences of different + authentication approaches (JWT, OAuth, OpenID) + +**Programming in Java** +- prefer *composition over inheritance* + - doesn't require type "linearization" + - use interfaces to combine different functionalities + - remains more understandable when complexity rises +- *separation of concerns* whenever possible + - interfaces will be simpler + - potentially independent components stay hidden otherwise + - enables modularity and code reuse + - reduces complexity and cognitive burden +- generics in Java are type-erased + - classes unfortunately can't implement the same interface with different generic types + - workaround: generic base interface, manual extension of this interface with concrete types +- fluent APIs provide nicer developer experience in most cases + - while they can take time and careful thought to implement +- builder pattern helps when class creation gets more complex + +**Project Lombok** +- not writing default getters and setters manually saves time and makes meaningful code more visible +- experimental `@Delegate` annotation + - can easily reduce the amount of required delegation code + - has limits due to generics, different visibilities and missing recursive support + +## Architecture +- **Reactive Streams**: Built with Spring WebFlux for non-blocking, event-driven IO +- **RESTful API**: Follows REST principles for simple, scalable and flexible service development +- **Security**: Spring Security integration for authentication and authorization +- **Database**: Uses PostgreSQL with R2DBC for reactive database access + +## Prerequisites +- Java 21 or later +- Gradle 8.0 or later +- Docker (uses PostgreSQL 13 or later) + +## Getting Started +### Local Development +1. **Clone the repository** + ```bash + git clone + cd recipe-api + ``` +2. **Start the database** + ```bash + docker-compose up -d + ``` +3. **Build and Run** + ```bash + ./gradlew bootRun + ``` + The application will be available at [`http://localhost:8080`](http://localhost:8080) + +## API Documentation +- [Scalar registry](https://registry.scalar.com/@tobias-haenel/apis/recipe-api/) +- [OpenAPI YAML](openapi/recipe-api.yaml). +- [OpenAPI YAML (bundled)](openapi/recipe-api-bundled.yaml). + +## Testing +1. **Run the test suite** + ```bash + ./gradlew test + ``` +2. **Check test results** + Open [`build/reports/tests/test/index.html`](build/reports/tests/test/index.html) in your browser + +## License +This project is licensed under the terms of the MIT license. See the [LICENSE](LICENSE) file for +details.