Java SDK for REST API 服务上的错误处理
我们正在构建一个 Java SDK,以简化对提供 REST API 的服务之一的访问。此 SDK 将由第三方开发人员使用。我正在努力寻找在SDK中实现更适合Java语言的错误处理的最佳模式。
假设我们有 rest 端点:。这可能会返回以下 HTTP 状态代码:GET /photos/{photoId}
- 401:用户未通过身份验证
- 403 : 用户无权访问此照片
- 404 : 没有带有该ID的照片
该服务如下所示:
interface RestService {
public Photo getPhoto(String photoID);
}
在上面的代码中,我还没有解决错误处理问题。我显然想为sdk的客户端提供一种方法来了解发生了哪个错误,并可能从中恢复。Java中的错误处理是使用异常完成的,所以让我们继续吧。但是,使用异常执行此操作的最佳方法是什么?
1. 具有有关错误信息的单个异常。
public Photo getPhoto(String photoID) throws RestServiceException;
public class RestServiceException extends Exception {
int statusCode;
...
}
然后,sdk 的客户端可以执行如下操作:
try {
Photo photo = getPhoto("photo1");
}
catch(RestServiceException e) {
swtich(e.getStatusCode()) {
case 401 : handleUnauthenticated(); break;
case 403 : handleUnauthorized(); break;
case 404 : handleNotFound(); break;
}
}
但是,我不太喜欢这个解决方案,主要有2个原因:
- 通过查看方法的签名,开发人员不知道他可能需要处理哪种错误情况。
- 开发人员需要直接处理HTTP状态代码,并知道它们在此方法上下文中的含义(显然,如果正确使用它们,很多时候含义是已知的,但情况可能并非总是如此)。
2. 具有错误的类层次结构
方法签名保留:
public Photo getPhoto(String photoID) throws RestServiceException;
但现在我们为每个错误类型创建异常:
public class UnauthenticatedException extends RestServiceException;
public class UnauthorizedException extends RestServiceException;
public class NotFoundException extends RestServiceException;
现在,SDK 的客户端可以执行如下操作:
try {
Photo photo = getPhoto("photo1");
}
catch(UnauthenticatedException e) {
handleUnauthorized();
}
catch(UnauthorizedException e) {
handleUnauthenticated();
}
catch(NotFoundException e) {
handleNotFound();
}
使用这种方法,开发人员不需要知道生成错误的HTTP状态代码,他只需要处理Java异常。另一个优点是,开发人员可能只捕获他想要处理的异常(与以前的情况不同,在以前的情况下,它必须捕获单个异常(),然后才决定他是否要处理它)。RestServiceException
但是,仍然存在一个问题。通过查看方法的签名,开发人员仍然不知道他可能需要处理的错误类型,因为我们在方法的签名中只有超类。
3. 具有错误的类层次结构 +在方法的签名中列出它们
好吧,现在想到的是将方法的签名更改为:
public Photo getPhoto(String photoID) throws UnauthenticatedException, UnauthorizedException, NotFoundException;
但是,将来可能会将新的错误情况添加到此 rest 终结点。这意味着向方法的签名添加新的异常,这将是对java api的重大更改。我们希望有一个更强大的解决方案,在描述的情况下不会导致对api的重大更改。
4. 具有错误的类层次结构(使用未选中的异常)+在方法的签名中列出它们
那么,未检查的异常呢?如果我们更改 RestServiceException 以扩展 RuntimeException:
public class RestServiceException extends RuntimeException
我们保留该方法的签名:
public Photo getPhoto(String photoID) throws UnauthenticatedException, UnauthorizedException, NotFoundException;
这样,我就可以向方法的签名添加新的异常,而不会破坏现有代码。但是,使用此解决方案,开发人员不会被迫捕获任何异常,也不会注意到他需要处理的错误情况,直到他仔细阅读文档(是的,对!)或注意到方法签名中的异常。
在这种情况下,错误处理的最佳实践是什么?
除了我提到的那些,还有其他(更好的)替代品吗?