Wer das erste mal einen klassischen Rest-Service mit Spring schreibt, also einen
@RestController
implementiert, der JSON (application/json; charset=utf-8) als
Reponse ausliefert, kommt irgendwann auf die Idee, ebenfalls Fehlerzustände
als JSON Response mit einem passenden HttpStatus Code auszuliefern.
Per Default erhält der Client den HTTP-Statuscode 500, wenn innerhalb des
@RestController
eine Exception geworfen wird. Das Ganze eingebettet in der
Standardfehlerseite des Webservers. Als Antwort auf einen Restservice
denkbar ungeeignet.
Eventuell möchte man einen Request auf die fachliche Korrektheit seiner
Parameter überprüfen. Falls die Prüfung negativ ausfällt, sollen spezielle
Http Status Codes (siehe Wikipedia HTTP StatusCodes)
ausgeliefert werden. Z.B. könnte sich der Statuscode 400 BAD REQUEST
oder
422 UNPROCESSABLE ENTITY
für das Beispiel anbieten.
Wie sieht eine Implementierung dazu aus? Auf GitHub habe ich ein
Beispielprojekt angelegt.
Der Webservice nimmt Benutzer Registrierungen entgegen und vermerkt,
ob der Benutzer dem Speichern von Cookies zugestimmt hat. Die Klasse
de.awtools.registration.CookieController
ist z.B. ein
einfacher @RestController
. Mit Spring hat man drei Möglichkeiten das
beschriebene Problem zu lösen. Ich habe mich hier für die Lösung
mit einem @ControllerAdvice
entschieden. Das hat den Vorteil, dass
dieser Advice für alle meine @RestController
gilt. Der ControllerAdvice
sieht folgendermaßen aus:
package de.awtools.registration.config;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import de.awtools.registration.RequestValidationException;
@ControllerAdvice
public class GlobalExceptionAdvice extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = { RequestValidationException.class })
protected ResponseEntity<Object> handleConflict(Exception ex,
WebRequest request) {
String bodyOfResponse = "Unknown";
if (ex instanceof RequestValidationException) {
RequestValidationException rvex = (RequestValidationException) ex;
bodyOfResponse = new StringBuilder().append('{')
.append("\"message\": \"")
.append(rvex.getValidation().getValidationCode().toString())
.append("\"").append('}').toString();
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
return handleExceptionInternal(ex, bodyOfResponse,
headers, HttpStatus.BAD_REQUEST, request);
}
}
Hier werden alle Exceptions vom Typ RequestValidationException
gefangen
und ausgewertet. D.h. der Http-Statuscode 400 wird ausgeliefert und die
Exception, bzw. die Nachricht aus der Exception, wird in ein einfaches
JSON Objekt verpackt.
Weitere Beispiele und Erklärungen:
Keine Kommentare:
Kommentar veröffentlichen