[英]Exception hierarchy for a REST service
我正在為我的REST服務設計一個異常類層次結構,並面臨以下問題。 請注意,該解決方案必須與Java 7兼容。
假設我正在建立一個管理考試的系統。 假設我有以下資源:
以及以下操作(以及其他操作):
請注意,對於某些操作,courseId是作為URL的一部分提供的,而對於其他操作,則是作為請求正文的一部分提供的。
我想設計一個異常類層次結構,以一致的方式向客戶端報告錯誤。 我希望每個異常類具有以下屬性:
現在讓我們關注類似於“無效ID”的錯誤。 我有以下要求:
如果將無效ID作為URL的一部分提供,則statusCode應該為404(未找到)。 如果它是作為請求主體的一部分提供的,則應為400(錯誤請求)。
errorCode / errorMessage應該從業務角度識別錯誤。 errorCode應該是一個可以唯一標識錯誤原因的數字(例如,1表示invalid-studentId,2表示invalid-courseId,等等),並且errorMessage應該以可人工修改的格式描述原因(例如,“ ID為ID的學生” [135]不存在。”)
問題是,如何將這兩個正交層次結構合並為一個異常類層次結構?
理想情況下,我將擁有以下異常類:
public abstract class ApiException extends Exception {
public abstract int getStatusCode();
public abstract int getErrorCode();
public abstract String getErrorMessage();
}
public abstract class NotFoundException extends ApiException {
public int getStatusCode() {
return 404;
}
}
public abstract class BadRequestException extends ApiException {
public int getStatusCode() {
return 400;
}
}
public abstract class InvalidCourseIdException extends ApiException {
private final String courseId;
public InvalidCourseIdException(final String courseId) {
this.courseId = courseId;
}
public int getErrorCode() {
return 2;
}
public String getErrorMessage() {
return "Course with ID [" + courseId + "] does not exist.";
}
}
public class CourseNotFoundException extends NotFoundException, InvalidCourseException {
public CourseNotFoundException(String courseId) {
super(courseId);
}
}
public class BadCourseException extends BadRequestException, InvalidCourseException {
public BadCourseException(String courseId) {
super(courseId);
}
}
...
當然,Java中不提供多重繼承。 如何設計Java 7兼容的類層次結構,遵循DRY原則(我想將每個常量值僅保留在一個位置)?
不要在Exception類中放入太多信息。 帶有您提到的屬性的ExamRestServiceException
完全可以。 如果要禁止某些屬性組合,則將構造函數設為私有並使用工廠方法,例如
...
private ExamRestServiceException(int httpStatusCode, int errorCode, int objectId, String message) {
// initialize your exception here
}
public ExamRestServiceException of(int httpStatusCode, int errorCode, int objectId, String message) {
// check the arguments here
return new ExamRestServiceException(httpStatusCode, errorCode, objectId, message);
}
....
編輯:如果您想比僅通過文檔更好地指導您的API用戶,您當然可以提供專門的工廠方法,例如
//e.g. needs no message, the HTTP status code is enough
public ExamRestServiceException connectionError(int httpStatusCode) {…}
要么
public ExamRestServiceException(int errorCode, String message) { … }
甚至針對每種錯誤情況提供一種方法。 順便說一下,有一個可以完美使用的HttpRetryException,您可能想重用而不是自己滾動。 如果(且僅當!)您擔心異常類變得太笨拙,則應考慮將其拆分為多個類。
llogiq的另一種方法是擁有異常生成器或工廠。
(a)提供一致的異常,(b)如果開發人員需要檢查代碼,則將代碼保存在一個地方; (c)使開發人員不必知道如果不需要知道如何構造單個異常。
已檢查異常的關鍵方面是您可以捕獲它們並從狀態中恢復。
異常不應按名稱傳遞原因。 如果是400或404,則無法恢復,因此應用程序應記錄狀態並中斷。
ApiException類足以啟動。
如果您害怕產生太多的代碼克隆。 您可以創建一個util類來收集所有案例。
final class ApiThrowables {
static final int BAD_REQUEST = 400;
static final int NOT_FOUND = 404;
public static ApiException newCourseIdNotFound(String courseId) {
return new ApiException(2, NOT_FOUND,"Course with ID [" + courseId + "] does not exist.");
}
public static ApiException newBadCourseId(String courseId) {
return new ApiException(2, BAD_REQUEST,"Course ID [" + courseId + "] is not valid.");
}
}
稍后,當您開發應用程序時,您可能會更改例外的設計,這種組合將使您能夠做到這一點。 當您使用繼承而不是組合時,您的代碼變成了中繼對象,這抑制了更改和重用的可能性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.