2025-08-12 17:29:18 +02:00
2025-08-12 17:26:50 +02:00
2025-08-12 17:26:50 +02:00
2025-08-12 17:29:02 +02:00
2025-08-12 17:26:50 +02:00
2025-08-12 17:26:50 +02:00
2025-08-12 17:26:50 +02:00
2025-08-12 17:26:50 +02:00
2025-08-12 17:26:50 +02:00
2025-08-12 17:26:50 +02:00
2025-08-12 17:28:41 +02:00
2025-08-12 17:29:18 +02:00
2025-08-12 17:26:50 +02:00

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. 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
    • extractingUserPrincipal 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
    git clone <repository-url>
    cd recipe-api
    
  2. Start the database
    docker-compose up -d
    
  3. Build and Run
    ./gradlew bootRun
    
    The application will be available at http://localhost:8080

API Documentation

Testing

  1. Run the test suite
    ./gradlew test
    
  2. Check test results Open build/reports/tests/test/index.html in your browser

License

This project is licensed under the terms of the MIT license. See the LICENSE file for details.

Description
Learning project: reactive REST API for managing recipes
Readme 195 KiB
Languages
Java 99.8%
HTML 0.2%