docs: add README
This commit is contained in:
133
README.md
Normal file
133
README.md
Normal 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.
|
||||
Reference in New Issue
Block a user