REST API Architectures in Java

Written by

in

When designing and implementing REST APIs in Java, architecture is typically evaluated across three dimensions:

  1. Application / Codebase Structure (How internal code is organized)
  2. System & Deployment Topology (How the system runs and scales across infrastructure)
  3. Execution & Concurrency Model (How Java processes HTTP requests and I/O)

1. Codebase & Application-Level Architectures

These patterns dictate how your Java code is structured inside a repository/service.

A. Layered (Controller–Service–Repository / N-Tier)

  • How it works: Code is arranged horizontally by technical concern:
    • Controller Layer (@RestController): Handles HTTP serialization/deserialization, validation, routing, and HTTP status codes.
    • Service Layer (@Service): Contains business logic, orchestration, and transactional boundaries (@Transactional).
    • Repository/Data Layer (@Repository): Communicates with the database (Spring Data JPA, Hibernate, jOOQ).
  • Common Java Stack: Standard Spring Boot, Jakarta EE (JAX-RS + EJB/CDI + JPA), Micronaut.
  • Best for: Small to medium applications, CRUD-heavy services, fast development cycles.

B. Hexagonal Architecture (Ports and Adapters) / Clean / Onion Architecture

  • How it works: The business domain is placed at the center, completely independent of frameworks, databases, and HTTP transports:
    • Inbound Ports & Adapters: Inbound ports define what the app can do; the REST controller is an inbound adapter that translates HTTP requests to call the port.
    • Outbound Ports & Adapters: Outbound ports define interfaces for data persistence/external APIs; repositories are outbound adapters.
  • Common Java Stack: Core Java domain (POJOs, no framework annotations), with Spring Boot/Quarkus wiring adapters via Dependency Injection.
  • Best for: Complex domain logic, long-lived enterprise applications, and scenarios where you want high testability without spinning up Spring contexts or databases.

C. Modular Monolith Architecture

  • How it works: A single deployable unit structured strictly into domain-bounded modules with explicit API boundaries between modules. It prevents the “spaghetti monolith” while avoiding the operational overhead of microservices.
  • Common Java Stack:Spring Modulith, ArchUnit (for boundary enforcement), Maven/Gradle multi-module builds.
  • Best for: Teams wanting clean domain boundaries and independence without managing distributed infrastructure.

D. CQRS (Command Query Responsibility Segregation) & Event Sourcing

  • How it works: Splits REST write endpoints (Commands: POST, PUT, DELETE) from read endpoints (Queries: GET). The read model and write model can use different data stores optimized for queries (e.g., Elasticsearch/Redis) and transactional writes (PostgreSQL).
  • Common Java Stack:Axon Framework, Spring Boot + Kafka, Debezium (for Change Data Capture).
  • Best for: High-read/high-write asymmetry, audit-heavy domains (finance, healthcare), and systems requiring an immutable history of domain events.

2. System & Deployment-Level Architectures

These patterns define how REST services are distributed across networks and infrastructure.

ArchitectureDescriptionCommon Java EcosystemBest For
Monolithic REST APISingle deployable JAR/WAR serving all REST endpoints.Spring Boot, Jakarta EE, QuarkusStartups, small teams, lower operational complexity.
Microservices REST APIFine-grained, independently deployable services per business capability communicating over REST/gRPC/Messaging.Spring Cloud, Quarkus, Micronaut, Netflix Eureka/Consul, Spring Cloud GatewayLarge teams, independently scaling domains.
Serverless / FaaS REST APIEndpoints executed as on-demand functions (e.g., AWS Lambda, GCP Cloud Functions).Quarkus / Micronaut with GraalVM Native Image, Spring Cloud FunctionIntermittent traffic, event-driven integrations, cost minimization at low volume.
BFF (Backend-for-Frontend)Specialized REST APIs tailored for specific frontends (Mobile, Web, Third-party) that aggregate calls to underlying services.Spring Cloud Gateway, GraphQL/REST hybrid in Spring BootApplications with varied consumer requirements across mobile, desktop, and public APIs.

3. Concurrency & Execution Models in Java

The underlying I/O model significantly influences how your REST API handles traffic and scales under high loads:

A. Classic Thread-Per-Request (Blocking I/O)

  • Mechanism: Every incoming HTTP request is assigned a dedicated operating system (platform) thread from a pool (e.g., Tomcat/Jetty worker threads).
  • Java Stack: Spring MVC (spring-boot-starter-web), standard Jakarta EE Servlet container.
  • Pros & Cons: Simple mental model and easy debugging, but high concurrent connection counts can cause memory pressure from OS thread overhead.

B. Virtual Threads / Project Loom (Modern Blocking I/O)

  • Mechanism: Introduced in Java 21. Standard synchronous, blocking code runs on lightweight “virtual threads” managed by the JVM instead of OS threads. When blocking on I/O, the JVM unmounts the virtual thread, enabling millions of concurrent requests with standard imperative syntax.
  • Java Stack: Java 21+ with Spring Boot 3.2+ (spring.threads.virtual.enabled=true), Quarkus, Helidon 4.
  • Pros & Cons: Gives the performance benefits of reactive programming without rewriting code in non-blocking/reactive paradigms.

C. Reactive / Event-Loop (Non-Blocking I/O)

  • Mechanism: Employs an event-loop model (typically Netty) with backpressure to handle thousands of requests per thread without blocking.
  • Java Stack:Spring WebFlux (Project Reactor), Eclipse Vert.x, Quarkus Reactive (SmallRye Mutiny).
  • Pros & Cons: Extremely memory-efficient for high streaming/I/O-heavy workloads; steeper learning curve, harder stack trace debugging, and requires non-blocking database drivers (e.g., R2DBC instead of JDBC).

Architecture Selection Guide

If your scenario is…Recommended ArchitectureRecommended Java Stack
Standard business CRUD APILayered Architecture + Virtual ThreadsJava 21+ / Spring Boot 3.x / Spring Data JPA
Complex enterprise domain with heavy business rulesHexagonal (Ports & Adapters)Plain Java Core + Spring Boot/Quarkus Adapters
Growing application, multiple domain teams, avoiding DevOps overheadModular MonolithSpring Modulith + ArchUnit
Independent team scaling, polyglot/decoupled deploymentsMicroservices ArchitectureSpring Cloud or Quarkus (with GraalVM)
Extreme concurrent I/O or event streamingReactive or Virtual ThreadedSpring WebFlux / Vert.x OR Spring Boot with Virtual Threads

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *