-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
EA-3236 add the error handling for record api and other validations
- Loading branch information
1 parent
9589d97
commit 840a335
Showing
10 changed files
with
321 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
record-api-web/src/main/java/eu/europeana/api/record/exception/GlobalExceptionHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package eu.europeana.api.record.exception; | ||
|
||
import eu.europeana.api.record.model.ApiErrorResponse; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import org.apache.logging.log4j.LogManager; | ||
import org.apache.logging.log4j.Logger; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
import org.springframework.web.bind.annotation.ResponseBody; | ||
import org.springframework.web.bind.annotation.RestControllerAdvice; | ||
|
||
/** | ||
* Global exception handler that catches all errors and logs the interesting ones | ||
* | ||
* @author Srishti Singh | ||
* Created on 24-08-2023 | ||
*/ | ||
@RestControllerAdvice | ||
@ResponseBody | ||
class GlobalExceptionHandler { | ||
|
||
private static final Logger LOG = LogManager.getLogger(GlobalExceptionHandler.class); | ||
|
||
// with Spring boot 3 (and Spring Framework 6) require a baseline of Jakarte EE 10 | ||
// You cannot use it with Java EE or Jakarte EE versions below that. | ||
// You have to remove the explicit dependency on jakarta.servlet-api from your pom.xml. | ||
// Java Servlet 4 is below the baseline and in particular still uses the package names starting with javax.servlet. | ||
// If you remove the explicit dependency, Spring will pull in transitively the correct one. | ||
// You then need to replace all imports starting with javax.servlet with javax replaced by jakarta | ||
|
||
protected void logException(RecordApiException e) { | ||
if (e.doLog()) { | ||
if (e.doLogStacktrace()) { | ||
LOG.error("Caught exception", e); | ||
} else { | ||
LOG.error("Caught exception: {}", e.getMessage()); | ||
} | ||
} | ||
|
||
} | ||
|
||
|
||
@ExceptionHandler | ||
public ResponseEntity<ApiErrorResponse> handleBaseException(RecordApiException e, HttpServletRequest httpRequest) { | ||
this.logException(e); | ||
ApiErrorResponse response = (new ApiErrorResponse.Builder(httpRequest, e, false)).setStatus(e.getResponseStatus().value()).setError | ||
(e.getResponseStatus().getReasonPhrase()).setMessage(e.doExposeMessage() ? e.getMessage() : null).setCode(e.getErrorCode()).build(); | ||
return ResponseEntity.status(e.getResponseStatus()).headers(this.createHttpHeaders()).body(response); | ||
} | ||
|
||
protected HttpHeaders createHttpHeaders() { | ||
HttpHeaders headers = new HttpHeaders(); | ||
headers.setContentType(MediaType.APPLICATION_JSON); | ||
return headers; | ||
} | ||
|
||
} |
21 changes: 21 additions & 0 deletions
21
record-api-web/src/main/java/eu/europeana/api/record/exception/HttpBadRequestException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package eu.europeana.api.record.exception; | ||
|
||
import org.springframework.http.HttpStatus; | ||
|
||
/** Exception thrown when an error occurs due to bad user input. */ | ||
public class HttpBadRequestException extends RecordApiException { | ||
|
||
public HttpBadRequestException(String msg) { | ||
super(msg); | ||
} | ||
|
||
@Override | ||
public boolean doLogStacktrace() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public HttpStatus getResponseStatus() { | ||
return HttpStatus.BAD_REQUEST; | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
...api-web/src/main/java/eu/europeana/api/record/exception/RecordAlreadyExistsException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package eu.europeana.api.record.exception; | ||
|
||
import org.springframework.http.HttpStatus; | ||
|
||
/** Exception thrown when a record already exists in the DB. */ | ||
public class RecordAlreadyExistsException extends RecordApiException { | ||
|
||
public RecordAlreadyExistsException(String about) { | ||
super("Record already exists for '" + about); | ||
} | ||
|
||
@Override | ||
public boolean doLogStacktrace() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public HttpStatus getResponseStatus() { | ||
return HttpStatus.BAD_REQUEST; | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
record-api-web/src/main/java/eu/europeana/api/record/exception/RecordApiException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package eu.europeana.api.record.exception; | ||
|
||
import org.springframework.http.HttpStatus; | ||
|
||
public class RecordApiException extends Exception { | ||
|
||
private static final long serialVersionUID = -1354471712894853562L; | ||
private final String errorCode; | ||
|
||
public RecordApiException(String msg, Throwable t) { | ||
this(msg, (String)null, t); | ||
} | ||
|
||
public RecordApiException(String msg, String errorCode, Throwable t) { | ||
super(msg, t); | ||
this.errorCode = errorCode; | ||
} | ||
|
||
public RecordApiException(String msg) { | ||
super(msg); | ||
this.errorCode = null; | ||
} | ||
|
||
public RecordApiException(String msg, String errorCode) { | ||
super(msg); | ||
this.errorCode = errorCode; | ||
} | ||
|
||
public boolean doLog() { | ||
return true; | ||
} | ||
|
||
public boolean doLogStacktrace() { | ||
return true; | ||
} | ||
|
||
public String getErrorCode() { | ||
return this.errorCode; | ||
} | ||
|
||
public boolean doExposeMessage() { | ||
return true; | ||
} | ||
|
||
public HttpStatus getResponseStatus() { | ||
return HttpStatus.INTERNAL_SERVER_ERROR; | ||
} | ||
} |
108 changes: 108 additions & 0 deletions
108
record-api-web/src/main/java/eu/europeana/api/record/model/ApiErrorResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package eu.europeana.api.record.model; | ||
|
||
import com.fasterxml.jackson.annotation.JsonFormat; | ||
import com.fasterxml.jackson.annotation.JsonInclude; | ||
import com.fasterxml.jackson.annotation.JsonPropertyOrder; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import org.springframework.util.StringUtils; | ||
|
||
import java.time.OffsetDateTime; | ||
import java.util.List; | ||
|
||
@JsonPropertyOrder({"success", "status", "error", "message", "timestamp", "path"}) | ||
@JsonInclude(JsonInclude.Include.NON_EMPTY) | ||
public class ApiErrorResponse { | ||
private final boolean success = false; | ||
private final int status; | ||
private final String error; | ||
private final String message; | ||
@JsonFormat( | ||
pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'" | ||
) | ||
private final OffsetDateTime timestamp = OffsetDateTime.now(); | ||
private final String path; | ||
private final String code; | ||
|
||
private ApiErrorResponse(int status, String error, String message, String path, String code) { | ||
this.status = status; | ||
this.error = error; | ||
this.message = message; | ||
this.path = path; | ||
this.code = code; | ||
} | ||
|
||
public String getError() { | ||
return this.error; | ||
} | ||
|
||
public boolean isSuccess() { | ||
return false; | ||
} | ||
|
||
public int getStatus() { | ||
return this.status; | ||
} | ||
|
||
public String getMessage() { | ||
return this.message; | ||
} | ||
|
||
public OffsetDateTime getTimestamp() { | ||
return this.timestamp; | ||
} | ||
|
||
public String getPath() { | ||
return this.path; | ||
} | ||
|
||
public String getCode() { | ||
return this.code; | ||
} | ||
|
||
public static class Builder { | ||
private int status; | ||
private String message; | ||
private String error; | ||
private final String path; | ||
private String code; | ||
|
||
public Builder(HttpServletRequest httpRequest, Exception e, boolean stacktraceEnabled) { | ||
this.path = getRequestPath(httpRequest); | ||
boolean includeErrorStack = false; | ||
String profileParamString = httpRequest.getParameter("profile"); | ||
if (StringUtils.hasLength(profileParamString)) { | ||
includeErrorStack = List.of(profileParamString.split(",")).contains("debug"); | ||
} | ||
|
||
} | ||
|
||
public ApiErrorResponse.Builder setStatus(int status) { | ||
this.status = status; | ||
return this; | ||
} | ||
|
||
public ApiErrorResponse.Builder setMessage(String message) { | ||
this.message = message; | ||
return this; | ||
} | ||
|
||
public ApiErrorResponse.Builder setError(String error) { | ||
this.error = error; | ||
return this; | ||
} | ||
|
||
public ApiErrorResponse.Builder setCode(String code) { | ||
this.code = code; | ||
return this; | ||
} | ||
|
||
public ApiErrorResponse build() { | ||
return new ApiErrorResponse(this.status, this.error, this.message, this.path, this.code); | ||
} | ||
} | ||
|
||
public static String getRequestPath(HttpServletRequest httpRequest) { | ||
return httpRequest.getQueryString() == null ? String.valueOf(httpRequest.getRequestURL()) : String.valueOf(httpRequest.getRequestURL().append("?").append(httpRequest.getQueryString())); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
server.port: 8080 | ||
|
||
spring: | ||
application: | ||
name: Record API | ||
|
||
server: | ||
error: | ||
include-message: always | ||
include-stacktrace: on_param | ||
include-exception: false |
Oops, something went wrong.