In my project, I added spring security using jwt. If token is missing or invalid, it will response with 401 and if permission is not set right, it will response with 403. I was wondering how I can customize the body of these two responses. I am creating response with custom messages using @ControllerAdvice
like this:
@ControllerAdvice
public class HealthDataProviderRestExceptionHandler {
private static final Logger LOG = LoggerFactory.getLogger(HealthDataProviderRestExceptionHandler.class);
private static final String INVALID_REQUEST_MSG = "Invalid Request.";
private static final String PROCESSING_ERROR_MSG = "Error while processing request.";
/**
* Customizes response for {@link HttpMessageNotReadableException}.
*
* @param ex the httpMessageNotReadableException
* @return HttpStatus.BAD_REQUEST
*/
@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<Object> handleIncorrectJsonException(HttpMessageNotReadableException ex) {
LOG.error(INVALID_REQUEST_MSG, ex);
return new ResponseEntity<>(getErrorMessage(INVALID_REQUEST_MSG, OperationOutcome.IssueType.INVALID),
setHeaders(), HttpStatus.BAD_REQUEST);
}
/**
* Customizes response for {@link MethodArgumentNotValidException}.
*
* @param ex the methodArgumentNotValidException
* @return HttpStatus.BAD_REQUEST
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
LOG.error(INVALID_REQUEST_MSG, ex);
return new ResponseEntity<>(getErrorMessage(INVALID_REQUEST_MSG, OperationOutcome.IssueType.INVALID),
setHeaders(), HttpStatus.BAD_REQUEST);
}
/**
* Customized response for {@link HealthDataProviderServiceException}.
*
* @param ex the HealthDataProviderServiceException
* @return HttpStatus.INTERNAL_SERVER_ERROR
*/
@ExceptionHandler(HealthDataProviderServiceException.class)
public ResponseEntity<Object> handleHealthDataProviderServiceException(
final HealthDataProviderServiceException ex) {
LOG.error(PROCESSING_ERROR_MSG, ex);
return new ResponseEntity<>(getErrorMessage(PROCESSING_ERROR_MSG, OperationOutcome.IssueType.EXCEPTION),
setHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
}
/**
* Customized response for {@link HealthDataProxyException}.
*
* @param ex HealthDataProxyException
* @return http status returned from proxy
*/
@ExceptionHandler(HealthDataProxyException.class)
public ResponseEntity<Object> handleHealthDataProxyException(final HealthDataProxyException ex) {
LOG.error(PROCESSING_ERROR_MSG, ex);
return new ResponseEntity<>(ex.getHealthDataProxyResponse(), setHeaders(), ex.getStatus());
}
/**
* Customizes response for {@link MethodArgumentTypeMismatchException }.
*
* @return HttpStatus.BAD_REQUEST
*/
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<Object> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) {
LOG.error(INVALID_REQUEST_MSG, ex);
return new ResponseEntity<>(getErrorMessage(INVALID_REQUEST_MSG, OperationOutcome.IssueType.INVALID),
setHeaders(), HttpStatus.BAD_REQUEST);
}
/**
* Customizes response for {@link ConstraintViolationException }.
*
* @return HttpStatus.BAD_REQUEST
*/
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Object> handleConstraintViolationException(ConstraintViolationException ex) {
LOG.error(INVALID_REQUEST_MSG, ex);
return new ResponseEntity<>(getErrorMessage(INVALID_REQUEST_MSG, OperationOutcome.IssueType.INVALID),
setHeaders(), HttpStatus.BAD_REQUEST);
}
/**
* Customizes response for {@link Exception}.
*
* @param ex the exception
* @return HttpStatus.INTERNAL_SERVER_ERROR
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleException(Exception ex) {
LOG.error(PROCESSING_ERROR_MSG, ex);
return new ResponseEntity<>(getErrorMessage(PROCESSING_ERROR_MSG, OperationOutcome.IssueType.EXCEPTION),
setHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
}
private MultiValueMap<String, String> setHeaders() {
MultiValueMap<String, String> headers = new HttpHeaders();
headers.set(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
headers.set(ACCEPT, MediaType.APPLICATION_JSON_VALUE);
return headers;
}
private String getErrorMessage(String message, OperationOutcome.IssueType issueType) {
OperationOutcome operationOutcome = new OperationOutcome();
OperationOutcome.OperationOutcomeIssueComponent component =
new OperationOutcome.OperationOutcomeIssueComponent();
component.setSeverity(OperationOutcome.IssueSeverity.ERROR);
component.setCode(issueType);
component.setDiagnostics(message);
operationOutcome.setId(String.valueOf(UUID.randomUUID()));
operationOutcome.addIssue(component);
return FhirContext.forR4().newJsonParser().encodeResourceToString(operationOutcome);
}
}
Based on different exception type, I am generating status and messages. But I am not sure what kind of exception it is throwing for 401 and 403. I am guessing some type of NotAuthorizedException
but not 100% sure.. How can I handle them with custom messages?