docs: add README

This commit is contained in:
2025-08-12 17:29:18 +02:00
parent aab7ff1452
commit 994066b856

133
README.md Normal file
View File

@@ -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 <repository-url>
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.