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