All Jakarta EE templates

Jakarta REST (JAX-RS)

JAX-RS resource methods, sub-resources, content negotiation, and exception mappers.

DevZone Tools1,280 copiesUpdated Mar 21, 2026Jakarta EEJava
# 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 Jakarta EE templates