Jakarta REST (JAX-RS)
JAX-RS resource methods, sub-resources, content negotiation, and exception mappers.
# CLAUDE.md — Jakarta REST (JAX-RS)
## Resources
- One resource class per top-level path. `@Path("/users")` on the class.
- Sub-resources for hierarchical paths. Methods can return another resource for nested routing:
```java
@Path("/{userId}/orders")
public OrderResource orders(@PathParam("userId") String userId) { return orderResource.forUser(userId); }
```
- Don't put 30 endpoints in one class. Split by sub-resource.
## Methods
- `@GET`, `@POST`, `@PUT`, `@PATCH`, `@DELETE`. Use the verb that matches semantics.
- `@Path("/{id}")` for path params. Use `@PathParam`, `@QueryParam`, `@HeaderParam`, `@FormParam` for binding.
- `@Produces(MediaType.APPLICATION_JSON)` and `@Consumes(MediaType.APPLICATION_JSON)` at the class level when consistent.
## Request bodies
- Pass POJOs as method parameters — JAX-RS uses the message body reader to deserialize.
- Validate with `@Valid` + Bean Validation:
```java
@POST
public Response create(@Valid CreateUserRequest req) { ... }
```
- Don't accept `String` and parse JSON yourself. Let the runtime do it.
## Responses
- Return `Response` for full control:
```java
return Response.status(201).entity(user).header("Location", uri).build();
```
- Return the entity directly when the status is always 200 and headers don't vary. Cleaner.
- For "not found", return `Response.status(404).build()` or throw a `NotFoundException`.
## Exception mappers
- `@Provider` class implementing `ExceptionMapper<X>`. The runtime auto-discovers it.
- One mapper per error type. Translate domain exceptions to HTTP responses here, not in resources.
```java
@Provider
public class NotFoundMapper implements ExceptionMapper<NotFoundDomainException> {
public Response toResponse(NotFoundDomainException e) {
return Response.status(404).entity(Map.of("error", e.getMessage())).build();
}
}
```
## Filters & interceptors
- `ContainerRequestFilter` / `ContainerResponseFilter` for cross-cutting: auth, logging, request id.
- `@PreMatching` filters run before the resource is matched (useful for auth).
- Use **interceptors** (`ReaderInterceptor`, `WriterInterceptor`) for body transformation.
## Content negotiation
- Default to JSON. Add other media types only when a real client needs them.
- Don't use `produces` to "version" APIs (`application/vnd.app.v2+json`). Use URL versioning for client clarity.
## Async
- `@Suspended AsyncResponse response` for non-blocking responses:
```java
@GET
public void list(@Suspended AsyncResponse response) {
service.fetchAsync().thenAccept(response::resume);
}
```
- For reactive/CompletionStage, return it directly — JAX-RS 2.1+ resumes automatically.
## Don't
- Don't put business logic in resources. Parse → call service → respond.
- Don't return JPA entities. Map to DTOs.
- Don't catch `Exception` in a resource method to translate. Use an `ExceptionMapper`.
- Don't use `@QueryParam` with a complex object expecting magic binding. JAX-RS handles primitives, strings, and types with a `valueOf(String)` constructor.
Other Java templates
Modern Java Rules
Java 21+ defaults: records, sealed types, pattern matching, virtual threads, var.
Java Testing with JUnit 5
JUnit 5 + AssertJ + Mockito + Testcontainers — opinionated test conventions.
Java Virtual Threads & Concurrency
Project Loom virtual threads, structured concurrency, and modern concurrent patterns.
Java Build (Maven & Gradle)
Build conventions, dependency management, multi-module projects, and CI patterns.
Java Streams & Collections
Streams API, immutable collections, Collectors, and idiomatic data manipulation.