Kapitel 38 · REST
REST Deep Dive: Fehler, Filter, Versionierung
ExceptionMapper, Container Filter, API-Versionen und Problem Details.
Fachliche Einordnung
REST Deep Dive: Fehler, Filter, Versionierung ist im Enterprise-Kontext kein isoliertes Thema. Es beantwortet die Frage, welche Verantwortung an welcher Stelle im System liegen soll. In einem Order-&-Billing-System entscheidet diese Ebene darueber, ob eine Bestellung nachvollziehbar angenommen, validiert, persistiert, abgerechnet und an Partner- oder Legacy-Systeme weitergegeben werden kann.
Eine typische Enterprise-Anfrage beginnt nicht im Service, sondern bereits am Rand: Reverse Proxy, TLS, Authentifizierung, Filter, Korrelation, Payload-Grenzen und Mapping muessen als zusammenhaengende Strecke verstanden werden. Jakarta trennt diese Zustaendigkeiten bewusst: Servlet behandelt den HTTP-Unterbau, REST modelliert Ressourcen, CDI verbindet Objekte, Validation prueft Eingaben und JTA sichert Konsistenz.
Technisches Modell
Das wichtigste mentale Modell lautet: API und Implementierung sind getrennt. Jakarta definiert Standards und Annotationen; die konkrete Runtime oder Library liefert das Verhalten. Dadurch kann dieselbe Fachidee auf Open Liberty, WildFly, Payara, TomEE, GlassFish oder in cloud-nativen Frameworks unterschiedlich betrieben werden.
Ausfuehrliches Beispiel
@Path("/orders")
@ApplicationScoped
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class OrderResource {
@Inject OrderApplicationService service;
@POST
@RolesAllowed("SALES")
public Response create(@Valid CreateOrderRequest request, @Context SecurityContext security) {
OrderId id = service.createOrder(request.customerId(), request.lines(), security.getUserPrincipal().getName());
return Response.created(URI.create("/orders/" + id.value()))
.entity(new OrderCreatedResponse(id.value(), "ACCEPTED"))
.build();
}
@GET
@Path("/{id}")
public OrderDto find(@PathParam("id") String id) {
return service.findOrder(new OrderId(id));
}
}
@Provider
public class BusinessExceptionMapper implements ExceptionMapper<BusinessException> {
public Response toResponse(BusinessException ex) {
var problem = new Problem("BUSINESS_RULE", ex.getMessage());
return Response.status(422).entity(problem).build();
}
}
Typische Fehler und bessere Variante
1. Fachlogik im technischen Adapter
Besser: Resource, Servlet oder Listener nur als Adapter nutzen. Die Entscheidung liegt in Application Service und Domain-Modell.
2. Zu breite Transaktion
Besser: Transaktionsgrenzen am Use Case schneiden, externe Calls ausserhalb oder ueber Outbox/JMS entkoppeln.
3. Provider-Magie ohne Dokumentation
Besser: Jede Implementierungsentscheidung in README, ADR oder design-patterns.md vermerken.
4. Keine Betriebsdiagnose
Besser: fachliche IDs, Trace-ID, Health Checks und technische Metriken von Anfang an einbauen.
Praxis-Checkliste
- Typ klar markiert: Spezifikation, Framework, Library, Runtime oder Methodik.
- Codebeispiel trennt Adapter, Application Service, Domain und Infrastruktur.
- Fehlerfall, Security und Transaktion sind erkennbar.
- Migration von Java EE zu Jakarta EE wurde beachtet.
- Teststrategie mit Unit-, Integration- oder Container-Test ist ableitbar.