rgoussu@goussu: ~/library/java/protocols
~/library/java/protocols cat rest.md

REST & HTTP APIs in Java

# Jakarta REST (JAX-RS) and its framework equivalents — Spring MVC/WebFlux, Quarkus REST, Micronaut HTTP — plus clients, OpenAPI and error conventions.

Conceptsaved 2026-08-09 #java#protocols#rest#http#frameworks

Overview

REST over HTTP/JSON is the default protocol for Java services, and the ecosystem offers two parallel programming models for it: the Jakarta REST standard (still widely called JAX-RS) with its pluggable implementations, and Spring's own annotation set, which won by adoption rather than standardisation. Quarkus and Micronaut each sit differently in that split — Quarkus implements the Jakarta annotations on its own reactive engine, Micronaut ships its own annotations with a compile-time twist. The concepts (resources, content negotiation, exception mapping) transfer across all four; only the annotations change.

Key points

  • Jakarta REST (JAX-RS) is the spec: @Path, @GET/@POST, @Produces/@Consumes, @PathParam/@QueryParam; extensibility through providers (MessageBodyReader/Writer, ExceptionMapper, filters and interceptors).
  • RESTEasy (Red Hat, WildFly) and Jersey (Eclipse, the reference implementation) are the two main Jakarta REST implementations.
  • Spring MVC is the servlet-stack equivalent: @RestController, @GetMapping, @RequestParam, @RequestBody; Spring WebFlux reuses the same annotations on a reactive Netty stack returning Mono/Flux.
  • Quarkus REST (formerly RESTEasy Reactive) implements the Jakarta REST annotations with build-time processing; endpoints can be blocking, reactive (Mutiny Uni), or run on virtual threads with @RunOnVirtualThread.
  • Micronaut HTTP uses its own @Controller/@Get annotations, processed at compile time — no runtime reflection — on a Netty server.
  • Clients: JDK java.net.http.HttpClient (no dependencies), Spring RestClient (synchronous, fluent) and WebClient (reactive), MicroProfile Rest Client (typed interface, used by Quarkus), and the declarative-interface libraries Feign/OpenFeign and Retrofit.
  • OpenAPI is generated per stack: springdoc-openapi for Spring Boot, SmallRye OpenAPI (MicroProfile OpenAPI) for Quarkus, Micronaut OpenAPI at compile time.
  • Errors: converge on RFC 9457 (formerly 7807) application/problem+json rather than ad-hoc error bodies.

Details

Server-side models compared

Concern Jakarta REST Spring MVC / WebFlux Quarkus REST Micronaut HTTP
Resource class @Path("/orders") @RestController + @RequestMapping Jakarta REST annotations @Controller("/orders")
Method + route @GET @Path("{id}") @GetMapping("/{id}") @GET @Path("{id}") @Get("/{id}")
Parameter binding @PathParam, @QueryParam, @HeaderParam @PathVariable, @RequestParam, @RequestHeader Jakarta REST + simplified plain parameters @PathVariable, @QueryValue
Body mapping entity parameter via MessageBodyReader @RequestBody via HttpMessageConverter entity parameter @Body
Error mapping ExceptionMapper<T> provider @ControllerAdvice + @ExceptionHandler ExceptionMapper or @ServerExceptionMapper @Error handlers
Async model CompletionStage, reactive extensions WebFlux Mono/Flux Mutiny Uni/Multi, virtual threads Reactor/CompletableFuture

The Jakarta REST provider model is its real substance: readers/writers handle entity (de)serialisation, ContainerRequestFilter/ContainerResponseFilter handle cross-cutting concerns, and everything is discovered via @Provider. Spring covers the same ground with HttpMessageConverters, HandlerInterceptors and @ControllerAdvice.

Clients

  • JDK HttpClient (java.net.http, since 11): HTTP/2, async sendAsync, zero dependencies — right answer for libraries and simple calls.
  • Spring RestClient: the modern synchronous client (Spring 6.1+), fluent API, superseding RestTemplate (maintenance mode); WebClient for reactive stacks.
  • MicroProfile Rest Client: annotate a Jakarta REST interface, get a typed client — the Quarkus-native option.
  • Declarative interfaces: Spring's HTTP interface clients (@HttpExchange), OpenFeign (Spring Cloud), Retrofit (Square) — same idea, different ecosystems.
  • Micronaut @Client generates the implementation at compile time.

Content negotiation & JSON binding

Accept/Content-Type negotiation is handled by all four stacks against the @Produces/produces = declarations. For JSON binding, Jackson is the de-facto standard (Spring, Micronaut, and the Quarkus default via quarkus-rest-jackson); JSON-B (Jakarta JSON Binding, implemented by Eclipse Yasson) is the standards-track alternative, common in Jakarta EE application servers. Jackson's module ecosystem (JavaTimeModule, records support, @JsonView) is usually the deciding factor.

Error conventions

Prefer RFC 9457 problem details (application/problem+json: type, title, status, detail, instance + extension members) over invented error envelopes. Spring 6 ships ProblemDetail and ErrorResponse natively (opt in via spring.mvc.problemdetails.enabled or by returning ProblemDetail); in Jakarta REST stacks an ExceptionMapper builds the problem body; Zalando's problem-spring-web predates and inspired the Spring support. Whatever the stack: map exceptions centrally, never leak stack traces, keep type URIs stable — they are API contract.

Examples

The same endpoint in the two dominant dialects:

// Jakarta REST (Quarkus, RESTEasy, Jersey)
@Path("/orders")
public class OrderResource {
    @GET @Path("{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Order get(@PathParam("id") long id) { ... }
}

// Spring MVC / WebFlux
@RestController
@RequestMapping("/orders")
class OrderController {
    @GetMapping("/{id}")
    Order get(@PathVariable long id) { ... }
}

Related